Mirror with some correction

Dependencies:   mbed FastIO FastPWM USBDevice

Committer:
mjr
Date:
Fri May 13 21:28:41 2016 +0000
Revision:
60:f38da020aa13
Parent:
59:94eb9265b6d7
Child:
76:7f5912b6340e
Try to bulletproof the Flash programming procedure by using techniques recommended in ARM forums; enhanced comments in main routine

Who changed what in which revision?

UserRevisionLine numberNew contents of line
mjr 2:c174f9ee414a 1 #include "FreescaleIAP.h"
mjr 2:c174f9ee414a 2
mjr 2:c174f9ee414a 3 //#define IAPDEBUG
mjr 2:c174f9ee414a 4
mjr 2:c174f9ee414a 5 enum FCMD {
mjr 2:c174f9ee414a 6 Read1s = 0x01,
mjr 2:c174f9ee414a 7 ProgramCheck = 0x02,
mjr 2:c174f9ee414a 8 ReadResource = 0x03,
mjr 2:c174f9ee414a 9 ProgramLongword = 0x06,
mjr 2:c174f9ee414a 10 EraseSector = 0x09,
mjr 2:c174f9ee414a 11 Read1sBlock = 0x40,
mjr 2:c174f9ee414a 12 ReadOnce = 0x41,
mjr 2:c174f9ee414a 13 ProgramOnce = 0x43,
mjr 2:c174f9ee414a 14 EraseAll = 0x44,
mjr 2:c174f9ee414a 15 VerifyBackdoor = 0x45
mjr 2:c174f9ee414a 16 };
mjr 2:c174f9ee414a 17
mjr 2:c174f9ee414a 18 static inline void run_command(FTFA_Type *);
mjr 2:c174f9ee414a 19 bool check_boundary(int address, unsigned int length);
mjr 2:c174f9ee414a 20 bool check_align(int address);
mjr 2:c174f9ee414a 21 IAPCode check_error(void);
mjr 2:c174f9ee414a 22
mjr 2:c174f9ee414a 23 FreescaleIAP::FreescaleIAP()
mjr 2:c174f9ee414a 24 {
mjr 2:c174f9ee414a 25 }
mjr 2:c174f9ee414a 26
mjr 2:c174f9ee414a 27 FreescaleIAP::~FreescaleIAP()
mjr 2:c174f9ee414a 28 {
mjr 2:c174f9ee414a 29 }
mjr 2:c174f9ee414a 30
mjr 59:94eb9265b6d7 31 // We use an assembly language implementation of the EXEC function in
mjr 59:94eb9265b6d7 32 // order to satisfy the requirement (mentioned in the hardware reference)
mjr 59:94eb9265b6d7 33 // that code that writes to Flash must reside in RAM. There's a potential
mjr 59:94eb9265b6d7 34 // for a deadlock if the code that triggers a Flash write operation is
mjr 59:94eb9265b6d7 35 // itself stored in Flash, as an instruction fetch to Flash can deadlock
mjr 59:94eb9265b6d7 36 // against the erase/write. In practice this seems to be rare, but I
mjr 59:94eb9265b6d7 37 // seem to be able to trigger it once in a while. (Which is to say that
mjr 59:94eb9265b6d7 38 // I can trigger occasional lock-ups during writes. It's not clear that
mjr 59:94eb9265b6d7 39 // the Flash bus deadlock is the actual cause, but the timing strongly
mjr 59:94eb9265b6d7 40 // suggests this.)
mjr 59:94eb9265b6d7 41 //
mjr 59:94eb9265b6d7 42 // The mbed tools don't have a way to put a C function in RAM. The mbed
mjr 59:94eb9265b6d7 43 // assembler can, though. So to get our invoking code into RAM, we have
mjr 59:94eb9265b6d7 44 // to write it in assembly. Fortunately, the code involved is very simple:
mjr 59:94eb9265b6d7 45 // just a couple of writes to the memory-mapped Flash controller register,
mjr 59:94eb9265b6d7 46 // and a looped read and bit test from the same location to wait until the
mjr 59:94eb9265b6d7 47 // operation finishes.
mjr 59:94eb9265b6d7 48 //
mjr 59:94eb9265b6d7 49 #define USE_ASM_EXEC 1
mjr 59:94eb9265b6d7 50 #if USE_ASM_EXEC
mjr 59:94eb9265b6d7 51 extern "C" void iapExecAsm(volatile uint8_t *);
mjr 59:94eb9265b6d7 52 #endif
mjr 59:94eb9265b6d7 53
mjr 2:c174f9ee414a 54 // execute an FTFA command
mjr 2:c174f9ee414a 55 static inline void run_command(FTFA_Type *ftfa)
mjr 2:c174f9ee414a 56 {
mjr 59:94eb9265b6d7 57 #if USE_ASM_EXEC
mjr 59:94eb9265b6d7 58 // Call our RAM-based assembly routine to do this work. The
mjr 59:94eb9265b6d7 59 // assembler routine implements the same ftfa->FSTAT register
mjr 59:94eb9265b6d7 60 // operations in the C alternative code below.
mjr 59:94eb9265b6d7 61 iapExecAsm(&ftfa->FSTAT);
mjr 59:94eb9265b6d7 62
mjr 59:94eb9265b6d7 63 #else // USE_ASM_EXEC
mjr 2:c174f9ee414a 64 // Clear possible old errors, start command, wait until done
mjr 2:c174f9ee414a 65 ftfa->FSTAT = FTFA_FSTAT_FPVIOL_MASK | FTFA_FSTAT_ACCERR_MASK | FTFA_FSTAT_RDCOLERR_MASK;
mjr 2:c174f9ee414a 66 ftfa->FSTAT = FTFA_FSTAT_CCIF_MASK;
mjr 60:f38da020aa13 67 while (!(ftfa->FSTAT & FTFA_FSTAT_CCIF_MASK)) ;
mjr 59:94eb9265b6d7 68
mjr 59:94eb9265b6d7 69 #endif // USE_ASM_EXEC
mjr 2:c174f9ee414a 70 }
mjr 2:c174f9ee414a 71
mjr 2:c174f9ee414a 72
mjr 2:c174f9ee414a 73 IAPCode FreescaleIAP::erase_sector(int address) {
mjr 2:c174f9ee414a 74 #ifdef IAPDEBUG
mjr 2:c174f9ee414a 75 printf("IAP: Erasing at %x\r\n", address);
mjr 2:c174f9ee414a 76 #endif
mjr 2:c174f9ee414a 77 if (check_align(address))
mjr 2:c174f9ee414a 78 return AlignError;
mjr 60:f38da020aa13 79
mjr 60:f38da020aa13 80 // divide the sector address into the three bytes for the three
mjr 60:f38da020aa13 81 // registers first, to reduce the risk of the operation being
mjr 60:f38da020aa13 82 // corrupted
mjr 60:f38da020aa13 83 uint8_t temp1 = (address >> 16) & 0xFF;
mjr 60:f38da020aa13 84 uint8_t temp2 = (address >> 8) & 0xFF;
mjr 60:f38da020aa13 85 uint8_t temp3 = address & 0xFF;
mjr 2:c174f9ee414a 86
mjr 60:f38da020aa13 87 // clear interrupts while working
mjr 60:f38da020aa13 88 __disable_irq();
mjr 60:f38da020aa13 89
mjr 60:f38da020aa13 90 // wait for any previous commands to clear
mjr 60:f38da020aa13 91 while (!(FTFA->FSTAT & FTFA_FSTAT_CCIF_MASK)) ;
mjr 60:f38da020aa13 92
mjr 60:f38da020aa13 93 // clear previous errors
mjr 60:f38da020aa13 94 FTFA->FSTAT = FTFA_FSTAT_FPVIOL_MASK | FTFA_FSTAT_ACCERR_MASK | FTFA_FSTAT_RDCOLERR_MASK;
mjr 60:f38da020aa13 95
mjr 60:f38da020aa13 96 // set up the command
mjr 2:c174f9ee414a 97 FTFA->FCCOB0 = EraseSector;
mjr 60:f38da020aa13 98 FTFA->FCCOB1 = temp1;
mjr 60:f38da020aa13 99 FTFA->FCCOB2 = temp2;
mjr 60:f38da020aa13 100 FTFA->FCCOB3 = temp3;
mjr 60:f38da020aa13 101
mjr 60:f38da020aa13 102 // execute it
mjr 60:f38da020aa13 103 run_command(FTFA);
mjr 2:c174f9ee414a 104
mjr 60:f38da020aa13 105 // re-enable interrupts
mjr 60:f38da020aa13 106 __enable_irq();
mjr 2:c174f9ee414a 107
mjr 2:c174f9ee414a 108 return check_error();
mjr 2:c174f9ee414a 109 }
mjr 2:c174f9ee414a 110
mjr 2:c174f9ee414a 111 IAPCode FreescaleIAP::program_flash(int address, const void *vp, unsigned int length) {
mjr 2:c174f9ee414a 112
mjr 2:c174f9ee414a 113 const char *data = (const char *)vp;
mjr 2:c174f9ee414a 114
mjr 2:c174f9ee414a 115 #ifdef IAPDEBUG
mjr 2:c174f9ee414a 116 printf("IAP: Programming flash at %x with length %d\r\n", address, length);
mjr 2:c174f9ee414a 117 #endif
mjr 2:c174f9ee414a 118 if (check_align(address))
mjr 2:c174f9ee414a 119 return AlignError;
mjr 2:c174f9ee414a 120
mjr 2:c174f9ee414a 121 IAPCode eraseCheck = verify_erased(address, length);
mjr 2:c174f9ee414a 122 if (eraseCheck != Success)
mjr 2:c174f9ee414a 123 return eraseCheck;
mjr 2:c174f9ee414a 124
mjr 2:c174f9ee414a 125 IAPCode progResult;
mjr 2:c174f9ee414a 126 for (int i = 0; i < length; i+=4) {
mjr 2:c174f9ee414a 127 progResult = program_word(address + i, data + i);
mjr 2:c174f9ee414a 128 if (progResult != Success)
mjr 2:c174f9ee414a 129 return progResult;
mjr 2:c174f9ee414a 130 }
mjr 2:c174f9ee414a 131
mjr 2:c174f9ee414a 132 return Success;
mjr 2:c174f9ee414a 133 }
mjr 2:c174f9ee414a 134
mjr 2:c174f9ee414a 135 uint32_t FreescaleIAP::flash_size(void) {
mjr 2:c174f9ee414a 136 uint32_t retval = (SIM->FCFG2 & 0x7F000000u) >> (24-13);
mjr 2:c174f9ee414a 137 if (SIM->FCFG2 & (1<<23)) //Possible second flash bank
mjr 2:c174f9ee414a 138 retval += (SIM->FCFG2 & 0x007F0000u) >> (16-13);
mjr 2:c174f9ee414a 139 return retval;
mjr 2:c174f9ee414a 140 }
mjr 2:c174f9ee414a 141
mjr 2:c174f9ee414a 142 IAPCode FreescaleIAP::program_word(int address, const char *data) {
mjr 2:c174f9ee414a 143 #ifdef IAPDEBUG
mjr 2:c174f9ee414a 144 printf("IAP: Programming word at %x, %d - %d - %d - %d\r\n", address, data[0], data[1], data[2], data[3]);
mjr 2:c174f9ee414a 145 #endif
mjr 2:c174f9ee414a 146 if (check_align(address))
mjr 2:c174f9ee414a 147 return AlignError;
mjr 60:f38da020aa13 148
mjr 60:f38da020aa13 149
mjr 60:f38da020aa13 150 // figure the three bytes of the address first
mjr 60:f38da020aa13 151 uint8_t temp1 = (address >> 16) & 0xFF;
mjr 60:f38da020aa13 152 uint8_t temp2 = (address >> 8) & 0xFF;
mjr 60:f38da020aa13 153 uint8_t temp3 = address & 0xFF;
mjr 2:c174f9ee414a 154
mjr 60:f38da020aa13 155 // get the data bytes into temps as well
mjr 60:f38da020aa13 156 uint8_t temp4 = data[3];
mjr 60:f38da020aa13 157 uint8_t temp5 = data[2];
mjr 60:f38da020aa13 158 uint8_t temp6 = data[1];
mjr 60:f38da020aa13 159 uint8_t temp7 = data[0];
mjr 60:f38da020aa13 160
mjr 60:f38da020aa13 161 // interrupts off while working
mjr 60:f38da020aa13 162 __disable_irq();
mjr 60:f38da020aa13 163
mjr 60:f38da020aa13 164 // wait for any previous commands to clear
mjr 60:f38da020aa13 165 while (!(FTFA->FSTAT & FTFA_FSTAT_CCIF_MASK)) ;
mjr 60:f38da020aa13 166
mjr 60:f38da020aa13 167 // clear previous errors
mjr 60:f38da020aa13 168 FTFA->FSTAT = FTFA_FSTAT_FPVIOL_MASK | FTFA_FSTAT_ACCERR_MASK | FTFA_FSTAT_RDCOLERR_MASK;
mjr 60:f38da020aa13 169
mjr 60:f38da020aa13 170 // Set up the command
mjr 2:c174f9ee414a 171 FTFA->FCCOB0 = ProgramLongword;
mjr 60:f38da020aa13 172 FTFA->FCCOB1 = temp1;
mjr 60:f38da020aa13 173 FTFA->FCCOB2 = temp2;
mjr 60:f38da020aa13 174 FTFA->FCCOB3 = temp3;
mjr 60:f38da020aa13 175 FTFA->FCCOB4 = temp4;
mjr 60:f38da020aa13 176 FTFA->FCCOB5 = temp5;
mjr 60:f38da020aa13 177 FTFA->FCCOB6 = temp6;
mjr 60:f38da020aa13 178 FTFA->FCCOB7 = temp7;
mjr 60:f38da020aa13 179
mjr 60:f38da020aa13 180 // execute the command
mjr 2:c174f9ee414a 181 run_command(FTFA);
mjr 2:c174f9ee414a 182
mjr 60:f38da020aa13 183 // interrupts on
mjr 60:f38da020aa13 184 __enable_irq();
mjr 60:f38da020aa13 185
mjr 60:f38da020aa13 186 // return error indication
mjr 2:c174f9ee414a 187 return check_error();
mjr 2:c174f9ee414a 188 }
mjr 2:c174f9ee414a 189
mjr 2:c174f9ee414a 190 /* Check if no flash boundary is violated
mjr 2:c174f9ee414a 191 Returns true on violation */
mjr 2:c174f9ee414a 192 bool check_boundary(int address, unsigned int length) {
mjr 2:c174f9ee414a 193 int temp = (address+length - 1) / SECTOR_SIZE;
mjr 2:c174f9ee414a 194 address /= SECTOR_SIZE;
mjr 2:c174f9ee414a 195 bool retval = (address != temp);
mjr 2:c174f9ee414a 196 #ifdef IAPDEBUG
mjr 2:c174f9ee414a 197 if (retval)
mjr 2:c174f9ee414a 198 printf("IAP: Boundary violation\r\n");
mjr 2:c174f9ee414a 199 #endif
mjr 2:c174f9ee414a 200 return retval;
mjr 2:c174f9ee414a 201 }
mjr 2:c174f9ee414a 202
mjr 2:c174f9ee414a 203 /* Check if address is correctly aligned
mjr 2:c174f9ee414a 204 Returns true on violation */
mjr 2:c174f9ee414a 205 bool check_align(int address) {
mjr 2:c174f9ee414a 206 bool retval = address & 0x03;
mjr 2:c174f9ee414a 207 #ifdef IAPDEBUG
mjr 2:c174f9ee414a 208 if (retval)
mjr 2:c174f9ee414a 209 printf("IAP: Alignment violation\r\n");
mjr 2:c174f9ee414a 210 #endif
mjr 2:c174f9ee414a 211 return retval;
mjr 2:c174f9ee414a 212 }
mjr 2:c174f9ee414a 213
mjr 2:c174f9ee414a 214 /* Check if an area of flash memory is erased
mjr 2:c174f9ee414a 215 Returns error code or Success (in case of fully erased) */
mjr 2:c174f9ee414a 216 IAPCode FreescaleIAP::verify_erased(int address, unsigned int length) {
mjr 2:c174f9ee414a 217 #ifdef IAPDEBUG
mjr 2:c174f9ee414a 218 printf("IAP: Verify erased at %x with length %d\r\n", address, length);
mjr 2:c174f9ee414a 219 #endif
mjr 2:c174f9ee414a 220
mjr 2:c174f9ee414a 221 if (check_align(address))
mjr 2:c174f9ee414a 222 return AlignError;
mjr 2:c174f9ee414a 223
mjr 60:f38da020aa13 224 // get the address into temps
mjr 60:f38da020aa13 225 uint8_t temp1 = (address >> 16) & 0xFF;
mjr 60:f38da020aa13 226 uint8_t temp2 = (address >> 8) & 0xFF;
mjr 60:f38da020aa13 227 uint8_t temp3 = address & 0xFF;
mjr 60:f38da020aa13 228
mjr 60:f38da020aa13 229 // get the length into temps as well
mjr 60:f38da020aa13 230 uint8_t temp4 = (length >> 10) & 0xFF;
mjr 60:f38da020aa13 231 uint8_t temp5 = (length >> 2) & 0xFF;
mjr 60:f38da020aa13 232
mjr 60:f38da020aa13 233 // interrupts off while working
mjr 60:f38da020aa13 234 __disable_irq();
mjr 60:f38da020aa13 235
mjr 60:f38da020aa13 236 // wait for any previous commands to clear
mjr 60:f38da020aa13 237 while (!(FTFA->FSTAT & FTFA_FSTAT_CCIF_MASK)) ;
mjr 60:f38da020aa13 238
mjr 60:f38da020aa13 239 // clear previous errors
mjr 60:f38da020aa13 240 FTFA->FSTAT = FTFA_FSTAT_FPVIOL_MASK | FTFA_FSTAT_ACCERR_MASK | FTFA_FSTAT_RDCOLERR_MASK;
mjr 60:f38da020aa13 241
mjr 60:f38da020aa13 242 // Set up the command
mjr 2:c174f9ee414a 243 FTFA->FCCOB0 = Read1s;
mjr 60:f38da020aa13 244 FTFA->FCCOB1 = temp1;
mjr 60:f38da020aa13 245 FTFA->FCCOB2 = temp2;
mjr 60:f38da020aa13 246 FTFA->FCCOB3 = temp3;
mjr 60:f38da020aa13 247 FTFA->FCCOB4 = temp4;
mjr 60:f38da020aa13 248 FTFA->FCCOB5 = temp5;
mjr 2:c174f9ee414a 249 FTFA->FCCOB6 = 0;
mjr 2:c174f9ee414a 250
mjr 60:f38da020aa13 251 // execute
mjr 2:c174f9ee414a 252 run_command(FTFA);
mjr 2:c174f9ee414a 253
mjr 60:f38da020aa13 254 // interrupts on
mjr 60:f38da020aa13 255 __enable_irq();
mjr 60:f38da020aa13 256
mjr 2:c174f9ee414a 257 IAPCode retval = check_error();
mjr 2:c174f9ee414a 258 if (retval == RuntimeError) {
mjr 2:c174f9ee414a 259 #ifdef IAPDEBUG
mjr 2:c174f9ee414a 260 printf("IAP: Flash was not erased\r\n");
mjr 2:c174f9ee414a 261 #endif
mjr 2:c174f9ee414a 262 return EraseError;
mjr 2:c174f9ee414a 263 }
mjr 2:c174f9ee414a 264 return retval;
mjr 2:c174f9ee414a 265
mjr 2:c174f9ee414a 266 }
mjr 2:c174f9ee414a 267
mjr 2:c174f9ee414a 268 /* Check if an error occured
mjr 2:c174f9ee414a 269 Returns error code or Success*/
mjr 2:c174f9ee414a 270 IAPCode check_error(void) {
mjr 2:c174f9ee414a 271 if (FTFA->FSTAT & FTFA_FSTAT_FPVIOL_MASK) {
mjr 2:c174f9ee414a 272 #ifdef IAPDEBUG
mjr 2:c174f9ee414a 273 printf("IAP: Protection violation\r\n");
mjr 2:c174f9ee414a 274 #endif
mjr 2:c174f9ee414a 275 return ProtectionError;
mjr 2:c174f9ee414a 276 }
mjr 2:c174f9ee414a 277 if (FTFA->FSTAT & FTFA_FSTAT_ACCERR_MASK) {
mjr 2:c174f9ee414a 278 #ifdef IAPDEBUG
mjr 2:c174f9ee414a 279 printf("IAP: Flash access error\r\n");
mjr 2:c174f9ee414a 280 #endif
mjr 2:c174f9ee414a 281 return AccessError;
mjr 2:c174f9ee414a 282 }
mjr 2:c174f9ee414a 283 if (FTFA->FSTAT & FTFA_FSTAT_RDCOLERR_MASK) {
mjr 2:c174f9ee414a 284 #ifdef IAPDEBUG
mjr 2:c174f9ee414a 285 printf("IAP: Collision error\r\n");
mjr 2:c174f9ee414a 286 #endif
mjr 2:c174f9ee414a 287 return CollisionError;
mjr 2:c174f9ee414a 288 }
mjr 2:c174f9ee414a 289 if (FTFA->FSTAT & FTFA_FSTAT_MGSTAT0_MASK) {
mjr 2:c174f9ee414a 290 #ifdef IAPDEBUG
mjr 2:c174f9ee414a 291 printf("IAP: Runtime error\r\n");
mjr 2:c174f9ee414a 292 #endif
mjr 2:c174f9ee414a 293 return RuntimeError;
mjr 2:c174f9ee414a 294 }
mjr 2:c174f9ee414a 295 #ifdef IAPDEBUG
mjr 2:c174f9ee414a 296 printf("IAP: No error reported\r\n");
mjr 2:c174f9ee414a 297 #endif
mjr 2:c174f9ee414a 298 return Success;
mjr 2:c174f9ee414a 299 }