| @@ -0,0 +1,767 @@ | |||
| /*********************************************************************** | |||
| * Copyright (c) 2014-2016 Ioannis Charalampidis | |||
| * Copyright (c) 2015 Simon Schulz - github.com/fishpepper | |||
| Copyright © 2019 Jean Michault. | |||
| This program is free software: you can redistribute it and/or modify | |||
| it under the terms of the GNU General Public License as published by | |||
| the Free Software Foundation, either version 3 of the License, or | |||
| (at your option) any later version. | |||
| This program is distributed in the hope that it will be useful, | |||
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| GNU General Public License for more details. | |||
| You should have received a copy of the GNU General Public License | |||
| along with this program. If not, see <https://www.gnu.org/licenses/>. | |||
| *************************************************************************/ | |||
| #include <wiringPi.h> | |||
| #include <stdint.h> | |||
| #include <stdio.h> | |||
| #include <stdlib.h> | |||
| #include <stdbool.h> | |||
| #include <time.h> | |||
| #include "CCDebugger.h" | |||
| /** | |||
| * Switch reset pin | |||
| */ | |||
| void cc_setDDDirection( uint8_t direction ); | |||
| /** | |||
| * Software-overridable instruction table that can be used | |||
| * for supporting other CCDebug-Compatible chips purely by software | |||
| */ | |||
| uint8_t instr[16]; | |||
| /** | |||
| * Local properties | |||
| */ | |||
| int pinRST=24; | |||
| int pinDC=28; | |||
| int pinDD=29; | |||
| uint8_t errorFlag=0; | |||
| uint8_t ddIsOutput=false; | |||
| uint8_t inDebugMode=false; | |||
| uint8_t cc_active=false; | |||
| /** | |||
| * Instruction table indices | |||
| */ | |||
| #define INSTR_VERSION 0 | |||
| #define I_HALT 1 | |||
| #define I_RESUME 2 | |||
| #define I_RD_CONFIG 3 | |||
| #define I_WR_CONFIG 4 | |||
| #define I_DEBUG_INSTR_1 5 | |||
| #define I_DEBUG_INSTR_2 6 | |||
| #define I_DEBUG_INSTR_3 7 | |||
| #define I_GET_CHIP_ID 8 | |||
| #define I_GET_PC 9 | |||
| #define I_READ_STATUS 10 | |||
| #define I_STEP_INSTR 11 | |||
| #define I_CHIP_ERASE 12 | |||
| #define I_SET_HW_BRKPNT 13 | |||
| #define I_GET_BM 14 | |||
| #define I_BURST_WRITE 15 | |||
| int cc_init( int pRST, int pDC, int pDD ) | |||
| { | |||
| if(wiringPiSetup() == -1){ | |||
| printf("no wiring pi detected\n"); | |||
| return 0; | |||
| } | |||
| pinRST=pRST; | |||
| pinDC=pDC; | |||
| pinDD=pDD; | |||
| // Prepare CC Pins | |||
| pinMode(pinDC, OUTPUT); | |||
| pinMode(pinDD, OUTPUT); | |||
| pinMode(pinRST, OUTPUT); | |||
| digitalWrite(pinDC, LOW); | |||
| digitalWrite(pinDD, LOW); | |||
| digitalWrite(pinRST, LOW); | |||
| // Prepare default direction | |||
| cc_setDDDirection(INPUT); | |||
| // Default CCDebug instruction set for CC254x | |||
| instr[INSTR_VERSION] = 1; | |||
| instr[I_HALT] = 0x40; | |||
| instr[I_RESUME] = 0x48; | |||
| instr[I_RD_CONFIG] = 0x20; | |||
| instr[I_WR_CONFIG] = 0x18; | |||
| instr[I_DEBUG_INSTR_1] = 0x51; | |||
| instr[I_DEBUG_INSTR_2] = 0x52; | |||
| instr[I_DEBUG_INSTR_3] = 0x53; | |||
| instr[I_GET_CHIP_ID] = 0x68; | |||
| instr[I_GET_PC] = 0x28; | |||
| instr[I_READ_STATUS] = 0x30; | |||
| instr[I_STEP_INSTR] = 0x58; | |||
| instr[I_CHIP_ERASE] = 0x10; | |||
| // We are active by default | |||
| cc_active = true; | |||
| }; | |||
| /** | |||
| * Activate/Deactivate debugger | |||
| */ | |||
| void cc_setActive( uint8_t on ) | |||
| { | |||
| // Reset error flag | |||
| errorFlag = CC_ERROR_NONE; | |||
| // Continue only if active | |||
| if (on == cc_active) return; | |||
| cc_active = on; | |||
| if (on) { | |||
| // Prepare CC Pins | |||
| pinMode(pinDC, OUTPUT); | |||
| pinMode(pinDD, OUTPUT); | |||
| pinMode(pinRST, OUTPUT); | |||
| digitalWrite(pinDC, LOW); | |||
| digitalWrite(pinDD, LOW); | |||
| digitalWrite(pinRST, LOW); | |||
| // Default direction is INPUT | |||
| cc_setDDDirection(INPUT); | |||
| } else { | |||
| // Before deactivating, exit debug mode | |||
| if (inDebugMode) | |||
| cc_exit(); | |||
| // Put everything in inactive mode | |||
| pinMode(pinDC, INPUT); | |||
| pinMode(pinDD, INPUT); | |||
| pinMode(pinRST, INPUT); | |||
| digitalWrite(pinDC, LOW); | |||
| digitalWrite(pinDD, LOW); | |||
| digitalWrite(pinRST, LOW); | |||
| } | |||
| } | |||
| /** | |||
| * Return the error flag | |||
| */ | |||
| uint8_t cc_error() | |||
| { | |||
| return errorFlag; | |||
| } | |||
| ///////////////////////////////////////////////////////////////////// | |||
| ///////////////////////////////////////////////////////////////////// | |||
| //// LOW LEVEL FUNCTIONS //// | |||
| ///////////////////////////////////////////////////////////////////// | |||
| ///////////////////////////////////////////////////////////////////// | |||
| /** | |||
| * Delay a particular number of cycles | |||
| */ | |||
| struct timespec tp={0,0}; | |||
| void cc_delay( unsigned char d ) | |||
| { | |||
| volatile unsigned char i = 50*d; | |||
| while( i-- ); | |||
| //tp.tv_nsec=40*d; | |||
| //nanosleep(&tp,NULL); | |||
| } | |||
| /** | |||
| * Enter debug mode | |||
| */ | |||
| uint8_t cc_enter() | |||
| { | |||
| if (!cc_active) { | |||
| errorFlag = CC_ERROR_NOT_ACTIVE; | |||
| return 0; | |||
| } | |||
| // ============= | |||
| // Reset error flag | |||
| errorFlag = CC_ERROR_NONE; | |||
| // Enter debug mode | |||
| digitalWrite(pinRST, LOW); | |||
| cc_delay(200); | |||
| digitalWrite(pinDC, HIGH); | |||
| cc_delay(3); | |||
| digitalWrite(pinDC, LOW); | |||
| cc_delay(3); | |||
| digitalWrite(pinDC, HIGH); | |||
| cc_delay(3); | |||
| digitalWrite(pinDC, LOW); | |||
| cc_delay(4); | |||
| digitalWrite(pinRST, HIGH); | |||
| cc_delay(200); | |||
| // We are now in debug mode | |||
| inDebugMode = 1; | |||
| // ============= | |||
| // Success | |||
| return 0; | |||
| }; | |||
| /** | |||
| * Write a uint8_t to the debugger | |||
| */ | |||
| uint8_t cc_write( uint8_t data ) | |||
| { | |||
| if (!cc_active) { | |||
| errorFlag = CC_ERROR_NOT_ACTIVE; | |||
| return 0; | |||
| }; | |||
| if (!inDebugMode) { | |||
| errorFlag = CC_ERROR_NOT_DEBUGGING; | |||
| return 0; | |||
| } | |||
| // ============= | |||
| uint8_t cnt; | |||
| // Make sure DD is on output | |||
| cc_setDDDirection(OUTPUT); | |||
| // Sent uint8_ts | |||
| for (cnt = 8; cnt; cnt--) { | |||
| // First put data bit on bus | |||
| if (data & 0x80) | |||
| digitalWrite(pinDD, HIGH); | |||
| else | |||
| digitalWrite(pinDD, LOW); | |||
| // Place clock on high (other end reads data) | |||
| digitalWrite(pinDC, HIGH); | |||
| // Shift & Delay | |||
| data <<= 1; | |||
| cc_delay(2); | |||
| // Place clock down | |||
| digitalWrite(pinDC, LOW); | |||
| cc_delay(2); | |||
| } | |||
| // ============= | |||
| return 0; | |||
| } | |||
| /** | |||
| * Wait until input is ready for reading | |||
| */ | |||
| uint8_t cc_switchRead(uint8_t maxWaitCycles) | |||
| { | |||
| if (!cc_active) { | |||
| errorFlag = CC_ERROR_NOT_ACTIVE; | |||
| return 0; | |||
| } | |||
| if (!inDebugMode) { | |||
| errorFlag = CC_ERROR_NOT_DEBUGGING; | |||
| return 0; | |||
| } | |||
| // ============= | |||
| uint8_t cnt; | |||
| uint8_t didWait = 0; | |||
| // Switch to input | |||
| cc_setDDDirection(INPUT); | |||
| // Wait at least 83 ns before checking state t(dir_change) | |||
| cc_delay(2); | |||
| // Wait for DD to go LOW (Chip is READY) | |||
| while (digitalRead(pinDD) == HIGH) { | |||
| // Do 8 clock cycles | |||
| for (cnt = 8; cnt; cnt--) { | |||
| digitalWrite(pinDC, HIGH); | |||
| cc_delay(2); | |||
| digitalWrite(pinDC, LOW); | |||
| cc_delay(2); | |||
| } | |||
| // Let next function know that we did wait | |||
| didWait = 1; | |||
| // Check if we ran out if wait cycles | |||
| if (!--maxWaitCycles) { | |||
| // If we are waiting for too long, we have lost the chip, | |||
| // so also assume we are out of debugging mode | |||
| errorFlag = CC_ERROR_NOT_WIRED; | |||
| inDebugMode = 0; | |||
| return 0; | |||
| } | |||
| } | |||
| // Wait t(sample_wait) | |||
| if (didWait) cc_delay(2); | |||
| // ============= | |||
| return 0; | |||
| } | |||
| /** | |||
| * Switch to output | |||
| */ | |||
| uint8_t cc_switchWrite() | |||
| { | |||
| cc_setDDDirection(OUTPUT); | |||
| return 0; | |||
| } | |||
| /** | |||
| * Read an input uint8_t | |||
| */ | |||
| uint8_t cc_read() | |||
| { | |||
| if (!cc_active) { | |||
| errorFlag = CC_ERROR_NOT_ACTIVE; | |||
| return 0; | |||
| } | |||
| // ============= | |||
| uint8_t cnt; | |||
| uint8_t data = 0; | |||
| // Switch to input | |||
| cc_setDDDirection(INPUT); | |||
| // Send 8 clock pulses if we are HIGH | |||
| for (cnt = 8; cnt; cnt--) { | |||
| digitalWrite(pinDC, HIGH); | |||
| cc_delay(2); | |||
| // Shift and read | |||
| data <<= 1; | |||
| if (digitalRead(pinDD) == HIGH) | |||
| data |= 0x01; | |||
| digitalWrite(pinDC, LOW); | |||
| cc_delay(2); | |||
| } | |||
| // ============= | |||
| return data; | |||
| } | |||
| /** | |||
| * Switch reset pin | |||
| */ | |||
| void cc_setDDDirection( uint8_t direction ) | |||
| { | |||
| // Switch direction if changed | |||
| if (direction == ddIsOutput) return; | |||
| ddIsOutput = direction; | |||
| // Handle new direction | |||
| if (ddIsOutput) { | |||
| digitalWrite(pinDD, LOW); // Disable pull-up | |||
| pinMode(pinDD, OUTPUT); // Enable output | |||
| digitalWrite(pinDD, LOW); // Switch to low | |||
| } else { | |||
| digitalWrite(pinDD, LOW); // Disable pull-up | |||
| pinMode(pinDD, INPUT); // Disable output | |||
| digitalWrite(pinDD, LOW); // Don't use output pull-up | |||
| } | |||
| } | |||
| ///////////////////////////////////////////////////////////////////// | |||
| ///////////////////////////////////////////////////////////////////// | |||
| //// HIGH LEVEL FUNCTIONS //// | |||
| ///////////////////////////////////////////////////////////////////// | |||
| ///////////////////////////////////////////////////////////////////// | |||
| /** | |||
| * Exit from debug mode | |||
| */ | |||
| uint8_t cc_exit() | |||
| { | |||
| if (!cc_active) { | |||
| errorFlag = CC_ERROR_NOT_ACTIVE; | |||
| return 0; | |||
| } | |||
| if (!inDebugMode) { | |||
| errorFlag = CC_ERROR_NOT_DEBUGGING; | |||
| return 0; | |||
| } | |||
| uint8_t bAns; | |||
| cc_write( instr[I_RESUME] ); // RESUME | |||
| cc_switchRead(250); | |||
| bAns = cc_read(); // debug status | |||
| cc_switchWrite(); | |||
| inDebugMode = 0; | |||
| return 0; | |||
| } | |||
| /** | |||
| * Get debug configuration | |||
| */ | |||
| uint8_t cc_getConfig() { | |||
| if (!cc_active) { | |||
| errorFlag = CC_ERROR_NOT_ACTIVE; | |||
| return 0; | |||
| } | |||
| if (!inDebugMode) { | |||
| errorFlag = CC_ERROR_NOT_DEBUGGING; | |||
| return 0; | |||
| } | |||
| uint8_t bAns; | |||
| cc_write( instr[I_RD_CONFIG] ); // RD_CONFIG | |||
| cc_switchRead(250); | |||
| bAns = cc_read(); // Config | |||
| cc_switchWrite(); | |||
| return bAns; | |||
| } | |||
| /** | |||
| * Set debug configuration | |||
| */ | |||
| uint8_t cc_setConfig( uint8_t config ) { | |||
| if (!cc_active) { | |||
| errorFlag = CC_ERROR_NOT_ACTIVE; | |||
| return 0; | |||
| } | |||
| if (!inDebugMode) { | |||
| errorFlag = CC_ERROR_NOT_DEBUGGING; | |||
| return 0; | |||
| } | |||
| uint8_t bAns; | |||
| cc_write( instr[I_WR_CONFIG] ); // WR_CONFIG | |||
| cc_write( config ); | |||
| cc_switchRead(250); | |||
| bAns = cc_read(); // Config | |||
| cc_switchWrite(); | |||
| return bAns; | |||
| } | |||
| /** | |||
| * Invoke a debug instruction with 1 opcode | |||
| */ | |||
| uint8_t cc_exec( uint8_t oc0 ) | |||
| { | |||
| if (!cc_active) { | |||
| errorFlag = CC_ERROR_NOT_ACTIVE; | |||
| return 0; | |||
| } | |||
| if (!inDebugMode) { | |||
| errorFlag = CC_ERROR_NOT_DEBUGGING; | |||
| return 0; | |||
| } | |||
| uint8_t bAns; | |||
| cc_write( instr[I_DEBUG_INSTR_1] ); // DEBUG_INSTR + 1b | |||
| cc_write( oc0 ); | |||
| cc_switchRead(250); | |||
| bAns = cc_read(); // Accumulator | |||
| cc_switchWrite(); | |||
| return bAns; | |||
| } | |||
| /** | |||
| * Invoke a debug instruction with 2 opcodes | |||
| */ | |||
| uint8_t cc_exec2( uint8_t oc0, uint8_t oc1 ) | |||
| { | |||
| if (!cc_active) { | |||
| errorFlag = CC_ERROR_NOT_ACTIVE; | |||
| return 0; | |||
| } | |||
| if (!inDebugMode) { | |||
| errorFlag = CC_ERROR_NOT_DEBUGGING; | |||
| return 0; | |||
| } | |||
| uint8_t bAns; | |||
| cc_write( instr[I_DEBUG_INSTR_2] ); // DEBUG_INSTR + 2b | |||
| cc_write( oc0 ); | |||
| cc_write( oc1 ); | |||
| cc_switchRead(250); | |||
| bAns = cc_read(); // Accumulator | |||
| cc_switchWrite(); | |||
| return bAns; | |||
| } | |||
| /** | |||
| * Invoke a debug instruction with 3 opcodes | |||
| */ | |||
| uint8_t cc_exec3( uint8_t oc0, uint8_t oc1, uint8_t oc2 ) | |||
| { | |||
| if (!cc_active) { | |||
| errorFlag = CC_ERROR_NOT_ACTIVE; | |||
| return 0; | |||
| } | |||
| if (!inDebugMode) { | |||
| errorFlag = CC_ERROR_NOT_DEBUGGING; | |||
| return 0; | |||
| } | |||
| uint8_t bAns; | |||
| cc_write( instr[I_DEBUG_INSTR_3] ); // DEBUG_INSTR + 3b | |||
| cc_write( oc0 ); | |||
| cc_write( oc1 ); | |||
| cc_write( oc2 ); | |||
| cc_switchRead(250); | |||
| bAns = cc_read(); // Accumulator | |||
| cc_switchWrite(); | |||
| return bAns; | |||
| } | |||
| /** | |||
| * Invoke a debug instruction with 1 opcode + 16-bit immediate | |||
| */ | |||
| uint8_t cc_execi( uint8_t oc0, unsigned short c0 ) | |||
| { | |||
| if (!cc_active) { | |||
| errorFlag = CC_ERROR_NOT_ACTIVE; | |||
| return 0; | |||
| } | |||
| if (!inDebugMode) { | |||
| errorFlag = CC_ERROR_NOT_DEBUGGING; | |||
| return 0; | |||
| } | |||
| uint8_t bAns; | |||
| cc_write( instr[I_DEBUG_INSTR_3] ); // DEBUG_INSTR + 3b | |||
| cc_write( oc0 ); | |||
| cc_write( (c0 >> 8) & 0xFF ); | |||
| cc_write( c0 & 0xFF ); | |||
| cc_switchRead(250); | |||
| bAns = cc_read(); // Accumulator | |||
| cc_switchWrite(); | |||
| return bAns; | |||
| } | |||
| /** | |||
| * Return chip ID | |||
| */ | |||
| unsigned short cc_getChipID() { | |||
| if (!cc_active) { | |||
| errorFlag = CC_ERROR_NOT_ACTIVE; | |||
| return 0; | |||
| } | |||
| if (!inDebugMode) { | |||
| errorFlag = CC_ERROR_NOT_DEBUGGING; | |||
| return 0; | |||
| } | |||
| unsigned short bAns; | |||
| uint8_t bRes; | |||
| cc_write( instr[I_GET_CHIP_ID] ); // GET_CHIP_ID | |||
| cc_switchRead(250); | |||
| bRes = cc_read(); // High order | |||
| bAns = bRes << 8; | |||
| bRes = cc_read(); // Low order | |||
| bAns |= bRes; | |||
| cc_switchWrite(); | |||
| return bAns; | |||
| } | |||
| /** | |||
| * Return PC | |||
| */ | |||
| unsigned short cc_getPC() { | |||
| if (!cc_active) { | |||
| errorFlag = CC_ERROR_NOT_ACTIVE; | |||
| return 0; | |||
| } | |||
| if (!inDebugMode) { | |||
| errorFlag = CC_ERROR_NOT_DEBUGGING; | |||
| return 0; | |||
| } | |||
| unsigned short bAns; | |||
| uint8_t bRes; | |||
| cc_write( instr[I_GET_PC] ); // GET_PC | |||
| cc_switchRead(250); | |||
| bRes = cc_read(); // High order | |||
| bAns = bRes << 8; | |||
| bRes = cc_read(); // Low order | |||
| bAns |= bRes; | |||
| cc_switchWrite(); | |||
| return bAns; | |||
| } | |||
| /** | |||
| * Return debug status | |||
| */ | |||
| uint8_t cc_getStatus() { | |||
| if (!cc_active) { | |||
| errorFlag = CC_ERROR_NOT_ACTIVE; | |||
| return 0; | |||
| } | |||
| if (!inDebugMode) { | |||
| errorFlag = CC_ERROR_NOT_DEBUGGING; | |||
| return 0; | |||
| } | |||
| uint8_t bAns; | |||
| cc_write( instr[I_READ_STATUS] ); // READ_STATUS | |||
| cc_switchRead(250); | |||
| bAns = cc_read(); // debug status | |||
| cc_switchWrite(); | |||
| return bAns; | |||
| } | |||
| /** | |||
| * Step instruction | |||
| */ | |||
| uint8_t cc_step() { | |||
| if (!cc_active) { | |||
| errorFlag = CC_ERROR_NOT_ACTIVE; | |||
| return 0; | |||
| } | |||
| if (!inDebugMode) { | |||
| errorFlag = CC_ERROR_NOT_DEBUGGING; | |||
| return 0; | |||
| } | |||
| uint8_t bAns; | |||
| cc_write( instr[I_STEP_INSTR] ); // STEP_INSTR | |||
| cc_switchRead(250); | |||
| bAns = cc_read(); // Accumulator | |||
| cc_switchWrite(); | |||
| return bAns; | |||
| } | |||
| /** | |||
| * resume instruction | |||
| */ | |||
| uint8_t cc_resume() { | |||
| if (!cc_active) { | |||
| errorFlag = CC_ERROR_NOT_ACTIVE; | |||
| return 0; | |||
| } | |||
| if (!inDebugMode) { | |||
| errorFlag = CC_ERROR_NOT_DEBUGGING; | |||
| return 0; | |||
| } | |||
| uint8_t bAns; | |||
| cc_write( instr[I_RESUME] ); //RESUME | |||
| cc_switchRead(250); | |||
| bAns = cc_read(); // Accumulator | |||
| cc_switchWrite(); | |||
| return bAns; | |||
| } | |||
| /** | |||
| * halt instruction | |||
| */ | |||
| uint8_t cc_halt() { | |||
| if (!cc_active) { | |||
| errorFlag = CC_ERROR_NOT_ACTIVE; | |||
| return 0; | |||
| } | |||
| if (!inDebugMode) { | |||
| errorFlag = CC_ERROR_NOT_DEBUGGING; | |||
| return 0; | |||
| } | |||
| uint8_t bAns; | |||
| cc_write( instr[I_HALT] ); //HALT | |||
| cc_switchRead(250); | |||
| bAns = cc_read(); // Accumulator | |||
| cc_switchWrite(); | |||
| return bAns; | |||
| } | |||
| /** | |||
| * Mass-erase all chip configuration & Lock Bits | |||
| */ | |||
| uint8_t cc_chipErase() | |||
| { | |||
| if (!cc_active) { | |||
| errorFlag = CC_ERROR_NOT_ACTIVE; | |||
| return 0; | |||
| }; | |||
| if (!inDebugMode) { | |||
| errorFlag = CC_ERROR_NOT_DEBUGGING; | |||
| return 0; | |||
| } | |||
| uint8_t bAns; | |||
| cc_write( instr[I_CHIP_ERASE] ); // CHIP_ERASE | |||
| cc_switchRead(250); | |||
| bAns = cc_read(); // Debug status | |||
| cc_switchWrite(); | |||
| return bAns; | |||
| } | |||
| /** | |||
| * Update the debug instruction table | |||
| */ | |||
| uint8_t cc_updateInstructionTable( uint8_t newTable[16] ) | |||
| { | |||
| // Copy table entries | |||
| for (uint8_t i=0; i<16; i++) | |||
| instr[i] = newTable[i]; | |||
| // Return the new version | |||
| return instr[INSTR_VERSION]; | |||
| } | |||
| /** | |||
| * Get the instruction table version | |||
| */ | |||
| uint8_t cc_getInstructionTableVersion() | |||
| { | |||
| // Return version of instruction table | |||
| return instr[INSTR_VERSION]; | |||
| } | |||
| @@ -0,0 +1,121 @@ | |||
| #ifndef CCDEBUGGER_H | |||
| #define CCDEBUGGER_H | |||
| #define CC_ERROR_NONE 0 | |||
| #define CC_ERROR_NOT_ACTIVE 1 | |||
| #define CC_ERROR_NOT_DEBUGGING 2 | |||
| #define CC_ERROR_NOT_WIRED 3 | |||
| int cc_init( int pinRST, int pinDC, int pinDD ); | |||
| void cc_delay( unsigned char d ); | |||
| uint8_t cc_error(); | |||
| //////////////////////////// | |||
| // High-Level interaction | |||
| //////////////////////////// | |||
| void cc_setActive( uint8_t on ); | |||
| /** | |||
| * Enter debug mode | |||
| */ | |||
| uint8_t cc_enter(); | |||
| /** | |||
| * Exit from debug mode | |||
| */ | |||
| uint8_t cc_exit(); | |||
| /** | |||
| * Execute a CPU instructuion | |||
| */ | |||
| uint8_t cc_exec( uint8_t oc0 ); | |||
| uint8_t cc_execi( uint8_t oc0, unsigned short c0 ); | |||
| uint8_t cc_exec2( uint8_t oc0, uint8_t oc1 ); | |||
| uint8_t cc_exec3( uint8_t oc0, uint8_t oc1, uint8_t oc2 ); | |||
| /** | |||
| * Return chip ID | |||
| */ | |||
| unsigned short cc_getChipID(); | |||
| /** | |||
| * Return PC | |||
| */ | |||
| unsigned short cc_getPC(); | |||
| /** | |||
| * Return debug status | |||
| */ | |||
| uint8_t cc_getStatus(); | |||
| /** | |||
| * resume program exec | |||
| */ | |||
| uint8_t cc_resume(); | |||
| /** | |||
| * halt program exec | |||
| */ | |||
| uint8_t cc_halt(); | |||
| /** | |||
| * Step a single instruction | |||
| */ | |||
| uint8_t cc_step(); | |||
| /** | |||
| * Get debug configuration | |||
| */ | |||
| uint8_t cc_getConfig(); | |||
| /** | |||
| * Set debug configuration | |||
| */ | |||
| uint8_t cc_setConfig( uint8_t config ); | |||
| /** | |||
| * Massive erasure on the chip | |||
| */ | |||
| uint8_t cc_chipErase(); | |||
| //////////////////////////// | |||
| // Low-level interaction | |||
| //////////////////////////// | |||
| /** | |||
| * Write to the debugger | |||
| */ | |||
| uint8_t cc_write( uint8_t data ); | |||
| /** | |||
| * Wait until we are ready to read & Switch to read mode | |||
| */ | |||
| uint8_t cc_switchRead( uint8_t maxWaitCycles ); | |||
| /** | |||
| * Switch to write mode | |||
| */ | |||
| uint8_t cc_switchWrite(); | |||
| /** | |||
| * Read from the debugger | |||
| */ | |||
| uint8_t cc_read(); | |||
| /** | |||
| * Update the debug instruction table | |||
| */ | |||
| uint8_t cc_updateInstructionTable( uint8_t newTable[16] ); | |||
| /** | |||
| * Get the instruction table version | |||
| */ | |||
| uint8_t cc_getInstructionTableVersion(); | |||
| #endif | |||
| @@ -0,0 +1,23 @@ | |||
| LDLIBS=-lwiringPi | |||
| CFLAGS=-g | |||
| LDFLAGS=-g | |||
| all: cc_chipid cc_read cc_write cc_erase | |||
| cc_erase : cc_erase.o CCDebugger.o | |||
| gcc $(LDFLAGS) -o $@ $^ $(LDLIBS) | |||
| cc_write : cc_write.o CCDebugger.o | |||
| gcc $(LDFLAGS) -o $@ $^ $(LDLIBS) | |||
| cc_read : cc_read.o CCDebugger.o | |||
| gcc $(LDFLAGS) -o $@ $^ $(LDLIBS) | |||
| cc_chipid : cc_chipid.o CCDebugger.o | |||
| gcc $(LDFLAGS) -o $@ $^ $(LDLIBS) | |||
| cc_chipid.o : cc_chipid.c CCDebugger.h | |||
| gcc $(CFLAGS) -c $*.c | |||
| CCDebugger.o : CCDebugger.c CCDebugger.h | |||
| gcc $(CFLAGS) -c $*.c | |||
| @@ -0,0 +1,37 @@ | |||
| /*********************************************************************** | |||
| Copyright © 2019 Jean Michault. | |||
| This program is free software: you can redistribute it and/or modify | |||
| it under the terms of the GNU General Public License as published by | |||
| the Free Software Foundation, either version 3 of the License, or | |||
| (at your option) any later version. | |||
| This program is distributed in the hope that it will be useful, | |||
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| GNU General Public License for more details. | |||
| You should have received a copy of the GNU General Public License | |||
| along with this program. If not, see <https://www.gnu.org/licenses/>. | |||
| *************************************************************************/ | |||
| #include <wiringPi.h> | |||
| #include <stdlib.h> | |||
| #include <stdio.h> | |||
| #include <stdbool.h> | |||
| #include <string.h> | |||
| #include <stdint.h> | |||
| #include "CCDebugger.h" | |||
| int main() | |||
| { | |||
| // initialize GPIO and debugger | |||
| cc_init(24,27,28); | |||
| // enter debug mode | |||
| cc_enter(); | |||
| // get ChipID : | |||
| uint16_t res; | |||
| res = cc_getChipID(); | |||
| printf(" ID = %04x.\n",res); | |||
| cc_setActive(false); | |||
| } | |||
| @@ -0,0 +1,41 @@ | |||
| /*********************************************************************** | |||
| Copyright © 2019 Jean Michault. | |||
| This program is free software: you can redistribute it and/or modify | |||
| it under the terms of the GNU General Public License as published by | |||
| the Free Software Foundation, either version 3 of the License, or | |||
| (at your option) any later version. | |||
| This program is distributed in the hope that it will be useful, | |||
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| GNU General Public License for more details. | |||
| You should have received a copy of the GNU General Public License | |||
| along with this program. If not, see <https://www.gnu.org/licenses/>. | |||
| *************************************************************************/ | |||
| #include <wiringPi.h> | |||
| #include <stdlib.h> | |||
| #include <stdio.h> | |||
| #include <stdbool.h> | |||
| #include <string.h> | |||
| #include <stdint.h> | |||
| #include "CCDebugger.h" | |||
| int main() | |||
| { | |||
| // initialize GPIO and debugger | |||
| cc_init(24,27,28); | |||
| // enter debug mode | |||
| cc_enter(); | |||
| // get ChipID : | |||
| uint16_t res; | |||
| res = cc_getChipID(); | |||
| printf(" ID = %04x.\n",res); | |||
| // erase flash | |||
| res = cc_chipErase(); | |||
| printf(" erase result = %04x.\n",res); | |||
| cc_setActive(false); | |||
| } | |||
| @@ -0,0 +1,107 @@ | |||
| /*********************************************************************** | |||
| Copyright © 2019 Jean Michault. | |||
| This program is free software: you can redistribute it and/or modify | |||
| it under the terms of the GNU General Public License as published by | |||
| the Free Software Foundation, either version 3 of the License, or | |||
| (at your option) any later version. | |||
| This program is distributed in the hope that it will be useful, | |||
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| GNU General Public License for more details. | |||
| You should have received a copy of the GNU General Public License | |||
| along with this program. If not, see <https://www.gnu.org/licenses/>. | |||
| *************************************************************************/ | |||
| #include <wiringPi.h> | |||
| #include <stdlib.h> | |||
| #include <stdio.h> | |||
| #include <stdbool.h> | |||
| #include <string.h> | |||
| #include <stdint.h> | |||
| #include "CCDebugger.h" | |||
| void writeHexLine(FILE * fic,uint8_t *buf, int len,int offset) | |||
| { | |||
| int i=0; | |||
| for(i=0 ; i<len ; i++) | |||
| if(buf[i] != 0xff) break; | |||
| if(i==len) return; | |||
| int sum=len+(offset&0xff)+((offset>>8)&0xff); | |||
| fprintf(fic,":%02X%04X00",len,offset); | |||
| for(int i=0 ; i<len;i++) | |||
| { | |||
| fprintf(fic,"%02X",buf[i]); | |||
| sum += buf[i]; | |||
| } | |||
| fprintf(fic,"%02X\n",(-sum)&0xff); | |||
| } | |||
| uint8_t buf1[1024]; | |||
| uint8_t buf2[1024]; | |||
| void read1k(int bank,uint16_t offset,uint8_t * buf) | |||
| { | |||
| // get FMAP | |||
| uint8_t res = cc_exec2(0xE5, 0xC7); | |||
| // select bank | |||
| res = (res & 0xF8) | (bank & 0x07); | |||
| res = cc_exec3(0x75, 0xC7, res); // MOV direct,#data | |||
| // Setup DPTR | |||
| cc_execi( 0x90, 0x8000+offset ); // MOV DPTR,#data16 | |||
| for(int i=0 ; i<1024 ;i++) | |||
| { | |||
| res = cc_exec ( 0xE0 ); // MOVX A,@DPTR | |||
| buf[i] = res; | |||
| res = cc_exec ( 0xA3 ); // INC DPTR | |||
| } | |||
| } | |||
| int main(int argc,char **argv) | |||
| { | |||
| if( argc <2 ) { fprintf(stderr,"usage : %s outfile\n",argv[0]); exit(1); } | |||
| FILE * ficout = fopen(argv[1],"w"); | |||
| if(!ficout) { fprintf(stderr," Can't open file %s.\n",argv[1]); exit(1); } | |||
| // initialize GPIO ports | |||
| cc_init(24,27,28); | |||
| // enter debug mode | |||
| cc_enter(); | |||
| // get ChipID : | |||
| uint16_t ID; | |||
| ID = cc_getChipID(); | |||
| printf(" ID = %04x.\n",ID); | |||
| uint16_t offset=0; | |||
| uint8_t bank=0; | |||
| int progress=1; | |||
| for( bank=0 ; bank<8 ; bank++) | |||
| { | |||
| printf(".");fflush(stdout); | |||
| if(! (bank&1)) | |||
| { | |||
| uint8_t sum=2+4+(bank/2); | |||
| fprintf(ficout,":02000004%04X%02X\n",bank/2,(-sum)&255 ); | |||
| } | |||
| offset=0; | |||
| int len=0; | |||
| uint8_t buf[17]; | |||
| for ( uint16_t i=0 ; i<32 ; i++ ) | |||
| { | |||
| do | |||
| { | |||
| read1k(bank,i*1024, buf1); | |||
| read1k(bank,i*1024, buf2); | |||
| } while(memcmp(buf1,buf2,1024)); | |||
| for(uint16_t j=0 ; j<64 ; j++) | |||
| writeHexLine(ficout,buf1+j*16, 16,(bank&1)*32*1024+ i*1024+j*16); | |||
| printf("\r reading %dk/256k",progress++);fflush(stdout); | |||
| } | |||
| } | |||
| fprintf(ficout,":00000001FF\n"); | |||
| // exit from debug | |||
| cc_setActive(false); | |||
| fclose(ficout); | |||
| } | |||
| @@ -0,0 +1,332 @@ | |||
| /*********************************************************************** | |||
| Copyright © 2019 Jean Michault. | |||
| This program is free software: you can redistribute it and/or modify | |||
| it under the terms of the GNU General Public License as published by | |||
| the Free Software Foundation, either version 3 of the License, or | |||
| (at your option) any later version. | |||
| This program is distributed in the hope that it will be useful, | |||
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| GNU General Public License for more details. | |||
| You should have received a copy of the GNU General Public License | |||
| along with this program. If not, see <https://www.gnu.org/licenses/>. | |||
| *************************************************************************/ | |||
| #include <wiringPi.h> | |||
| #include <stdlib.h> | |||
| #include <stdio.h> | |||
| #include <stdbool.h> | |||
| #include <string.h> | |||
| #include <stdint.h> | |||
| #include <unistd.h> | |||
| #include "CCDebugger.h" | |||
| uint8_t buffer[601]; | |||
| uint8_t data[260]; | |||
| uint8_t buf1[1024]; | |||
| uint8_t buf2[1024]; | |||
| struct page | |||
| { | |||
| uint32_t minoffset,maxoffset; | |||
| uint8_t datas[2048]; | |||
| } Pages[128]; | |||
| void readXDATA(uint16_t offset,uint8_t *bytes, int len) | |||
| { | |||
| cc_execi(0x90, offset ); //MOV DPTR,#data16 | |||
| for ( int i=0 ; i<len;i++) | |||
| { | |||
| bytes[i] = cc_exec(0xE0); //MOVX A,@DPTR | |||
| cc_exec(0xA3); // INC DPTR | |||
| } | |||
| } | |||
| void writeXDATA(uint16_t offset,uint8_t *bytes, int len) | |||
| { | |||
| cc_execi(0x90,offset); //MOV DPTR,#data16 | |||
| for ( int i=0 ; i<len;i++) | |||
| { | |||
| cc_exec2(0x74,bytes[i]); // MOV A,#data | |||
| cc_exec(0xF0); //MOVX @DPTR,A | |||
| cc_exec(0xA3); // INC DPTR | |||
| } | |||
| } | |||
| void readPage(int page,uint8_t *buf) | |||
| { | |||
| uint8_t bank=page>>4; | |||
| // get FMAP | |||
| uint8_t res = cc_exec2(0xE5, 0xC7); | |||
| // select bank | |||
| res = (res & 0xF8) | (bank & 0x07); | |||
| res = cc_exec3(0x75, 0xC7, res); // MOV direct,#data | |||
| // calculer l'adresse de destination | |||
| uint32_t offset = ((page&0xf)<<11) + Pages[page].minoffset; | |||
| // Setup DPTR | |||
| cc_execi( 0x90, 0x8000+offset ); // MOV DPTR,#data16 | |||
| for(int i=0 ; i<2048 ;i++) | |||
| { | |||
| res = cc_exec ( 0xE0 ); // MOVX A,@DPTR | |||
| buf[i] = res; | |||
| res = cc_exec ( 0xA3 ); // INC DPTR | |||
| } | |||
| } | |||
| uint8_t verif1[2048]; | |||
| uint8_t verif2[2048]; | |||
| int verifPage(int page) | |||
| { | |||
| do | |||
| { | |||
| readPage(page,verif1); | |||
| readPage(page,verif2); | |||
| } while (memcmp(verif1,verif2,2048)); | |||
| for(int i=Pages[page].minoffset ; i<Pages[page].maxoffset ;i++) | |||
| { | |||
| if(verif1[i] != Pages[page].datas[i]) | |||
| { | |||
| printf("\nerror at 0x%x, 0x%x instead of 0x%x\n",i,verif1[i],Pages[page].datas[i]); | |||
| return 1; | |||
| } | |||
| } | |||
| return 0; | |||
| } | |||
| int writePage(int page) | |||
| { | |||
| uint8_t bank=page>>4; | |||
| // get FMAP | |||
| uint8_t res = cc_exec2(0xE5, 0xC7); | |||
| // select bank | |||
| res = (res & 0xF8) | (bank & 0x07); | |||
| res = cc_exec3(0x75, 0xC7, res); // MOV direct,#data | |||
| // calculer l'adresse de destination | |||
| uint32_t offset = ((page&0xf)<<11) + Pages[page].minoffset; | |||
| uint32_t len = Pages[page].maxoffset-Pages[page].minoffset+1; | |||
| // configure DMA-0 pour DEBUG --> RAM | |||
| uint8_t dma_desc0[8]; | |||
| dma_desc0[0] = 0x62;// src[15:8] | |||
| dma_desc0[1] = 0x60;// src[7:0] | |||
| dma_desc0[2] = 0x00;// dest[15:8] | |||
| dma_desc0[3] = 0x00;// dest[7:0] | |||
| dma_desc0[4] = (len>>8)&0xff; | |||
| dma_desc0[5] = (len&0xff); | |||
| dma_desc0[6] = 0x1f; //wordsize=0,tmode=0,trig=0x1F | |||
| dma_desc0[7] = 0x19;//srcinc=0,destinc=1,irqmask=1,m8=0,priority=1 | |||
| writeXDATA( 0x1000, dma_desc0, 8 ); | |||
| cc_exec3( 0x75, 0xD4, 0x00); | |||
| cc_exec3( 0x75, 0xD5, 0x10); | |||
| // configure DMA-1 pour RAM --> FLASH | |||
| uint8_t dma_desc1[8]; | |||
| dma_desc1[0] = 0x00;// src[15:8] | |||
| dma_desc1[1] = 0x00;// src[7:0] | |||
| dma_desc1[2] = 0x62;// dest[15:8] | |||
| dma_desc1[3] = 0x73;// dest[7:0] | |||
| dma_desc1[4] = (len>>8)&0xff; | |||
| dma_desc1[5] = (len&0xff); | |||
| dma_desc1[6] = 0x12; //wordsize=0,tmode=0,trig=0x12 | |||
| dma_desc1[7] = 0x42;//srcinc=1,destinc=0,irqmask=1,m8=0,priority=2 | |||
| writeXDATA( 0x1008, dma_desc1, 8 ); | |||
| cc_exec3( 0x75, 0xD2, 0x08); | |||
| cc_exec3( 0x75, 0xD3, 0x10); | |||
| // clear flash status | |||
| readXDATA(0x6270, &res, 1); | |||
| res &=0x1F; | |||
| writeXDATA(0x6270, &res, 1); | |||
| // clear DMAIRQ 0 et 1 | |||
| res = cc_exec2(0xE5, 0xD1); | |||
| res &= ~1; | |||
| res &= ~2; | |||
| cc_exec3(0x75,0xD1,res); | |||
| // disarm DMA Channel 0 et 1 | |||
| res = cc_exec2(0xE5, 0xD6); | |||
| res &= ~1; | |||
| res &= ~2; | |||
| cc_exec3(0x75,0xD6,res); | |||
| // Upload to RAM through DMA-0 | |||
| // arm DMA channel 0 : | |||
| res = cc_exec2(0xE5, 0xD6); | |||
| res |= 1; | |||
| cc_exec3(0x75,0xD6,res); | |||
| cc_delay(200); | |||
| // transfert de données en mode burst | |||
| cc_write(0x80|( (len>>8)&0x7) ); | |||
| cc_write(len&0xff); | |||
| for(int i=0 ; i<len ;i++) | |||
| cc_write(Pages[page].datas[i+Pages[page].minoffset]); | |||
| // wait DMA end : | |||
| do | |||
| { | |||
| cc_delay(100); | |||
| res = cc_exec2(0xE5, 0xD1); | |||
| res &= 1; | |||
| } while (res==0); | |||
| // Clear DMA IRQ flag | |||
| res = cc_exec2(0xE5, 0xD1); | |||
| res &= ~1; | |||
| cc_exec3(0x75,0xD1,res); | |||
| // disarm DMA Channel 1 | |||
| res = cc_exec2(0xE5, 0xD6); | |||
| res &= ~2; | |||
| cc_exec3(0x75,0xD6,res); | |||
| // écrire l'adresse de destination dans FADDRH FADDRL | |||
| offset = page<<11 + Pages[page].minoffset; | |||
| res=(offset>>2)&0xff; | |||
| writeXDATA( 0x6271, &res,1); | |||
| res=(offset>>10)&0xff; | |||
| writeXDATA( 0x6272, &res,1); | |||
| // arm DMA channel 1 : | |||
| res = cc_exec2(0xE5, 0xD6); | |||
| res |= 2; | |||
| cc_exec3(0x75,0xD6,res); | |||
| cc_delay(200); | |||
| // lancer la copie vers la FLASH | |||
| readXDATA(0x6270, &res, 1); | |||
| res |= 2; | |||
| writeXDATA(0x6270, &res, 1); | |||
| // wait DMA end : | |||
| do | |||
| { | |||
| sleep(1); | |||
| res = cc_exec2(0xE5, 0xD1); | |||
| res &= 2; | |||
| } while (res==0); | |||
| // vérifie qu'il n'y a pas eu de flash abort | |||
| readXDATA(0x6270, &res, 1); | |||
| if (res&0x20) | |||
| { | |||
| fprintf(stderr," flash error !!!\n"); | |||
| exit(1); | |||
| } | |||
| } | |||
| int main(int argc,char **argv) | |||
| { | |||
| if( argc <2 ) { fprintf(stderr,"usage : %s file_to_flash\n",argv[0]); exit(1); } | |||
| FILE * ficin = fopen(argv[1],"r"); | |||
| if(!ficin) { fprintf(stderr," Can't open file %s.\n",argv[1]); exit(1); } | |||
| // on initialise les ports GPIO et le debugger | |||
| cc_init(24,27,28); | |||
| // entrée en mode debug | |||
| cc_enter(); | |||
| // envoi de la commande getChipID : | |||
| uint16_t ID; | |||
| ID = cc_getChipID(); | |||
| printf(" ID = %04x.\n",ID); | |||
| for (int page=0 ; page<128 ; page++) | |||
| { | |||
| memset(Pages[page].datas,0xff,2048); | |||
| Pages[page].minoffset=0xffff; | |||
| Pages[page].maxoffset=0; | |||
| } | |||
| uint16_t ela=0; // extended linear address | |||
| uint32_t sla=0; // start linear address | |||
| // read hex file | |||
| int line=0; | |||
| int maxpage=0; | |||
| while(fgets(buffer,600,ficin)) | |||
| { | |||
| int sum=0,cksum,type; | |||
| uint32_t addr,len; | |||
| line++; | |||
| if(line%10==0) { printf("\r reading line %d.");fflush(stdout); } | |||
| if(buffer[0] != ':') { fprintf(stderr,"incorrect hex file ( : missing)\n"); exit(1); } | |||
| if(strlen(buffer)<3 ) { fprintf(stderr,"incorrect hex file ( incomplete line)\n"); exit(1); } | |||
| if(!sscanf(buffer+1,"%02x",&len)) { fprintf(stderr,"incorrect hex file (incorrect length\n"); exit(1); } | |||
| if(strlen(buffer)<(11 + (len * 2))) { fprintf(stderr,"incorrect hex file ( incomplete line)\n"); exit(1); } | |||
| if(!sscanf(buffer+3,"%04x",&addr)) { fprintf(stderr,"incorrect hex file (incorrect addr)\n"); exit(1); } | |||
| if(!sscanf(buffer+7,"%02x",&type)) { fprintf(stderr,"incorrect hex file (incorrect record type\n"); exit(1); } | |||
| if(type == 4) | |||
| { | |||
| if(!sscanf(buffer+9,"%04x",&ela)) { fprintf(stderr,"incorrect hex file (incorrect extended addr)\n"); exit(1); } | |||
| sla=ela<<16; | |||
| continue; | |||
| } | |||
| if(type == 5) | |||
| { | |||
| if(!sscanf(buffer+9,"%08x",&sla)) { fprintf(stderr,"incorrect hex file (incorrect extended addr)\n"); exit(1); } | |||
| ela = sla>>16; | |||
| continue; | |||
| } | |||
| if(type==1) // EOF | |||
| { | |||
| break; | |||
| } | |||
| if(type) { fprintf(stderr,"incorrect hex file (record type %d not implemented\n",type); exit(1); } | |||
| sum = (len & 255) + ((addr >> 8) & 255) + (addr & 255) + (type & 255); | |||
| int i; | |||
| for( i=0 ; i<len ; i++) | |||
| { | |||
| if(!sscanf(buffer+9+2*i,"%02x",&data[i])) { fprintf(stderr,"incorrect hex file (incorrect data)\n"); exit(1); } | |||
| sum+=data[i]; | |||
| } | |||
| if(!sscanf(buffer+9+2*i,"%02x",&cksum)) { fprintf(stderr,"incorrect hex file line %d (incorrect checksum)\n",line); exit(1); } | |||
| if ( ((sum & 255) + (cksum & 255)) & 255 ) { fprintf(stderr,"incorrect hex file line %d (bad checksum) %x %x\n",line,(-sum)&255,cksum); exit(1); } | |||
| // stock datas | |||
| int page= (sla+addr)>>11; | |||
| if (page>maxpage) maxpage=page; | |||
| uint16_t start=(sla+addr)&0x7ff; | |||
| if(start+len> 2048) | |||
| { | |||
| if (page+1>maxpage) maxpage=page+1; | |||
| memcpy(&Pages[page+1].datas[0] | |||
| ,data,(start+len-2048)); | |||
| if(0 < Pages[page].minoffset) Pages[page].minoffset=0; | |||
| if( (start+len-2048-1) > Pages[page].maxoffset) Pages[page].maxoffset=start+len-2048-1; | |||
| len=2048-start; | |||
| } | |||
| memcpy(&Pages[page].datas[start] | |||
| ,data,len); | |||
| if(start < Pages[page].minoffset) Pages[page].minoffset=start; | |||
| if( (start+len-1) > Pages[page].maxoffset) Pages[page].maxoffset=start+len-1; | |||
| } | |||
| printf("\n file loaded (%d lines read).\n",line); | |||
| // activer DMA | |||
| uint8_t conf=cc_getConfig(); | |||
| conf &= ~0x4; | |||
| cc_setConfig(conf); | |||
| for (int page=0 ; page <= maxpage ; page++) | |||
| { | |||
| if(Pages[page].maxoffset<Pages[page].minoffset) continue; | |||
| printf("\rwriting page %3d/%3d.",page+1,maxpage+1); | |||
| fflush(stdout); | |||
| writePage(page); | |||
| } | |||
| printf("\n"); | |||
| // lire les données et les vérifier | |||
| int badPage=0; | |||
| for (int page=0 ; page <= maxpage ; page++) | |||
| { | |||
| if(Pages[page].maxoffset<Pages[page].minoffset) continue; | |||
| printf("\rverifying page %3d/%3d.",page+1,maxpage+1); | |||
| fflush(stdout); | |||
| badPage += verifPage(page); | |||
| } | |||
| printf("\n"); | |||
| if (!badPage) | |||
| printf(" flash OK.\n"); | |||
| else | |||
| printf(" Errors found in %d pages.\n",badPage); | |||
| // sortie du mode debug et désactivation : | |||
| cc_setActive(false); | |||
| fclose(ficin); | |||
| } | |||