Mirror with some correction
Dependencies: mbed FastIO FastPWM USBDevice
FreescaleIAP/FreescaleIAP.cpp@116:7a67265d7c19, 2021-10-01 (annotated)
- Committer:
- arnoz
- Date:
- Fri Oct 01 08:19:46 2021 +0000
- Revision:
- 116:7a67265d7c19
- Parent:
- 82:4f6209cb5c33
- Correct information regarding your last merge
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
mjr | 79:682ae3171a08 | 1 | // FreescaleIAP - custom version |
mjr | 76:7f5912b6340e | 2 | // |
mjr | 79:682ae3171a08 | 3 | // This is a simplified version of Erik Olieman's FreescaleIAP, a flash |
mjr | 79:682ae3171a08 | 4 | // memory writer for Freescale boards. This version combines erase, write, |
mjr | 79:682ae3171a08 | 5 | // and verify into a single API call. The caller only has to give us a |
mjr | 79:682ae3171a08 | 6 | // buffer (of any length) to write, and the address to write it to, and |
mjr | 79:682ae3171a08 | 7 | // we'll do the whole thing - essentially a memcpy() to flash. |
mjr | 76:7f5912b6340e | 8 | // |
mjr | 79:682ae3171a08 | 9 | // This version uses an assembler implementation of the core code that |
mjr | 79:682ae3171a08 | 10 | // launches an FTFA command and waits for completion, to minimize the |
mjr | 79:682ae3171a08 | 11 | // size of the code and to ensure that it's placed in RAM. The KL25Z |
mjr | 79:682ae3171a08 | 12 | // flash controller prohibits any flash reads while an FTFA command is |
mjr | 79:682ae3171a08 | 13 | // executing. This includes instruction fetches; any instruction fetch |
mjr | 79:682ae3171a08 | 14 | // from flash while an FTFA command is running will fail, which will |
mjr | 79:682ae3171a08 | 15 | // freeze the CPU. Placing the execute/wait code in RAM ensures that |
mjr | 79:682ae3171a08 | 16 | // the wait loop itself won't trigger a fetch. It's also vital to disable |
mjr | 79:682ae3171a08 | 17 | // interrupts while the execute/wait code is running, to ensure that we |
mjr | 79:682ae3171a08 | 18 | // don't jump to an ISR in flash during the wait. |
mjr | 76:7f5912b6340e | 19 | // |
mjr | 79:682ae3171a08 | 20 | // Despite the dire warnings in the hardware reference manual about putting |
mjr | 79:682ae3171a08 | 21 | // the FTFA execute/wait code in RAM, it doesn't actually appear to be |
mjr | 79:682ae3171a08 | 22 | // necessary, as long as the wait loop is very small (in terms of machine |
mjr | 79:682ae3171a08 | 23 | // code instruction count). In testing, Erik has found that a flash-resident |
mjr | 79:682ae3171a08 | 24 | // version of the code is stable, and further found (by testing combinations |
mjr | 79:682ae3171a08 | 25 | // of cache control settings via the platform control register, MCM_PLACR) |
mjr | 79:682ae3171a08 | 26 | // that the stability comes from the loop fitting into CPU cache, which |
mjr | 79:682ae3171a08 | 27 | // allows the loop to execute without any fetches taking place. Even so, |
mjr | 79:682ae3171a08 | 28 | // I'm keeping the RAM version, out of an abundance of caution: just in |
mjr | 79:682ae3171a08 | 29 | // case there are any rare or oddball conditions (interrupt timing, say) |
mjr | 79:682ae3171a08 | 30 | // where the cache trick breaks. Putting the code in RAM seems pretty |
mjr | 79:682ae3171a08 | 31 | // much guaranteed to work, whereas the cache trick seems somewhat to be |
mjr | 79:682ae3171a08 | 32 | // relying on a happy accident, and I personally don't know the M0+ |
mjr | 79:682ae3171a08 | 33 | // architecture well enough to be able to convince myself that it really |
mjr | 79:682ae3171a08 | 34 | // will work under all conditions. There doesn't seem to be any benefit |
mjr | 79:682ae3171a08 | 35 | // to not using the assembler, either, as it's very simple code and takes |
mjr | 79:682ae3171a08 | 36 | // up little RAM (about 40 bytes). |
mjr | 79:682ae3171a08 | 37 | |
mjr | 76:7f5912b6340e | 38 | |
mjr | 2:c174f9ee414a | 39 | #include "FreescaleIAP.h" |
mjr | 79:682ae3171a08 | 40 | |
mjr | 2:c174f9ee414a | 41 | //#define IAPDEBUG |
mjr | 76:7f5912b6340e | 42 | |
mjr | 76:7f5912b6340e | 43 | // assembly interface |
mjr | 76:7f5912b6340e | 44 | extern "C" { |
mjr | 79:682ae3171a08 | 45 | // Execute the current FTFA command and wait for completion. |
mjr | 79:682ae3171a08 | 46 | // This is an assembler implementation that runs entirely in RAM, |
mjr | 79:682ae3171a08 | 47 | // to ensure strict compliance with the prohibition on reading |
mjr | 79:682ae3171a08 | 48 | // flash (for instruction fetches or any other reason) during FTFA |
mjr | 79:682ae3171a08 | 49 | // execution. |
mjr | 79:682ae3171a08 | 50 | void iapExecAndWait(); |
mjr | 76:7f5912b6340e | 51 | } |
mjr | 76:7f5912b6340e | 52 | |
mjr | 2:c174f9ee414a | 53 | enum FCMD { |
mjr | 2:c174f9ee414a | 54 | Read1s = 0x01, |
mjr | 2:c174f9ee414a | 55 | ProgramCheck = 0x02, |
mjr | 2:c174f9ee414a | 56 | ReadResource = 0x03, |
mjr | 2:c174f9ee414a | 57 | ProgramLongword = 0x06, |
mjr | 2:c174f9ee414a | 58 | EraseSector = 0x09, |
mjr | 2:c174f9ee414a | 59 | Read1sBlock = 0x40, |
mjr | 2:c174f9ee414a | 60 | ReadOnce = 0x41, |
mjr | 2:c174f9ee414a | 61 | ProgramOnce = 0x43, |
mjr | 2:c174f9ee414a | 62 | EraseAll = 0x44, |
mjr | 2:c174f9ee414a | 63 | VerifyBackdoor = 0x45 |
mjr | 2:c174f9ee414a | 64 | }; |
mjr | 2:c174f9ee414a | 65 | |
mjr | 79:682ae3171a08 | 66 | // Get the size of the flash memory on the device |
mjr | 79:682ae3171a08 | 67 | uint32_t FreescaleIAP::flashSize(void) |
mjr | 76:7f5912b6340e | 68 | { |
mjr | 76:7f5912b6340e | 69 | uint32_t retval = (SIM->FCFG2 & 0x7F000000u) >> (24-13); |
mjr | 77:0b96f6867312 | 70 | if (SIM->FCFG2 & (1<<23)) // Possible second flash bank |
mjr | 76:7f5912b6340e | 71 | retval += (SIM->FCFG2 & 0x007F0000u) >> (16-13); |
mjr | 76:7f5912b6340e | 72 | return retval; |
mjr | 76:7f5912b6340e | 73 | } |
mjr | 79:682ae3171a08 | 74 | |
mjr | 79:682ae3171a08 | 75 | // Check if an error occurred |
mjr | 79:682ae3171a08 | 76 | static FreescaleIAP::IAPCode checkError(void) |
mjr | 76:7f5912b6340e | 77 | { |
mjr | 79:682ae3171a08 | 78 | if (FTFA->FSTAT & FTFA_FSTAT_FPVIOL_MASK) { |
mjr | 79:682ae3171a08 | 79 | #ifdef IAPDEBUG |
mjr | 79:682ae3171a08 | 80 | printf("IAP: Protection violation\r\n"); |
mjr | 79:682ae3171a08 | 81 | #endif |
mjr | 79:682ae3171a08 | 82 | return FreescaleIAP::ProtectionError; |
mjr | 79:682ae3171a08 | 83 | } |
mjr | 79:682ae3171a08 | 84 | if (FTFA->FSTAT & FTFA_FSTAT_ACCERR_MASK) { |
mjr | 79:682ae3171a08 | 85 | #ifdef IAPDEBUG |
mjr | 79:682ae3171a08 | 86 | printf("IAP: Flash access error\r\n"); |
mjr | 79:682ae3171a08 | 87 | #endif |
mjr | 79:682ae3171a08 | 88 | return FreescaleIAP::AccessError; |
mjr | 79:682ae3171a08 | 89 | } |
mjr | 79:682ae3171a08 | 90 | if (FTFA->FSTAT & FTFA_FSTAT_RDCOLERR_MASK) { |
mjr | 79:682ae3171a08 | 91 | #ifdef IAPDEBUG |
mjr | 79:682ae3171a08 | 92 | printf("IAP: Collision error\r\n"); |
mjr | 79:682ae3171a08 | 93 | #endif |
mjr | 79:682ae3171a08 | 94 | return FreescaleIAP::CollisionError; |
mjr | 79:682ae3171a08 | 95 | } |
mjr | 79:682ae3171a08 | 96 | if (FTFA->FSTAT & FTFA_FSTAT_MGSTAT0_MASK) { |
mjr | 79:682ae3171a08 | 97 | #ifdef IAPDEBUG |
mjr | 79:682ae3171a08 | 98 | printf("IAP: Runtime error\r\n"); |
mjr | 79:682ae3171a08 | 99 | #endif |
mjr | 79:682ae3171a08 | 100 | return FreescaleIAP::RuntimeError; |
mjr | 79:682ae3171a08 | 101 | } |
mjr | 79:682ae3171a08 | 102 | return FreescaleIAP::Success; |
mjr | 76:7f5912b6340e | 103 | } |
mjr | 79:682ae3171a08 | 104 | |
mjr | 79:682ae3171a08 | 105 | // check for proper address alignment |
mjr | 79:682ae3171a08 | 106 | static bool checkAlign(int address) |
mjr | 76:7f5912b6340e | 107 | { |
mjr | 76:7f5912b6340e | 108 | bool retval = address & 0x03; |
mjr | 76:7f5912b6340e | 109 | #ifdef IAPDEBUG |
mjr | 76:7f5912b6340e | 110 | if (retval) |
mjr | 76:7f5912b6340e | 111 | printf("IAP: Alignment violation\r\n"); |
mjr | 76:7f5912b6340e | 112 | #endif |
mjr | 76:7f5912b6340e | 113 | return retval; |
mjr | 76:7f5912b6340e | 114 | } |
mjr | 79:682ae3171a08 | 115 | |
mjr | 79:682ae3171a08 | 116 | // clear errors in the FTFA |
mjr | 79:682ae3171a08 | 117 | static void clearErrors() |
mjr | 79:682ae3171a08 | 118 | { |
mjr | 79:682ae3171a08 | 119 | // wait for any previous command to complete |
mjr | 79:682ae3171a08 | 120 | while (!(FTFA->FSTAT & FTFA_FSTAT_CCIF_MASK)) ; |
mjr | 79:682ae3171a08 | 121 | |
mjr | 79:682ae3171a08 | 122 | // clear the error bits |
mjr | 79:682ae3171a08 | 123 | if (FTFA->FSTAT & (FTFA_FSTAT_ACCERR_MASK | FTFA_FSTAT_FPVIOL_MASK)) |
mjr | 79:682ae3171a08 | 124 | FTFA->FSTAT |= FTFA_FSTAT_ACCERR_MASK | FTFA_FSTAT_FPVIOL_MASK; |
mjr | 79:682ae3171a08 | 125 | } |
mjr | 79:682ae3171a08 | 126 | |
mjr | 79:682ae3171a08 | 127 | static FreescaleIAP::IAPCode eraseSector(int address) |
mjr | 79:682ae3171a08 | 128 | { |
mjr | 79:682ae3171a08 | 129 | #ifdef IAPDEBUG |
mjr | 79:682ae3171a08 | 130 | printf("IAP: Erasing sector at %x\r\n", address); |
mjr | 79:682ae3171a08 | 131 | #endif |
mjr | 79:682ae3171a08 | 132 | |
mjr | 79:682ae3171a08 | 133 | // ensure proper alignment |
mjr | 79:682ae3171a08 | 134 | if (checkAlign(address)) |
mjr | 79:682ae3171a08 | 135 | return FreescaleIAP::AlignError; |
mjr | 79:682ae3171a08 | 136 | |
mjr | 79:682ae3171a08 | 137 | // clear errors |
mjr | 79:682ae3171a08 | 138 | clearErrors(); |
mjr | 79:682ae3171a08 | 139 | |
mjr | 79:682ae3171a08 | 140 | // Set up the command |
mjr | 79:682ae3171a08 | 141 | FTFA->FCCOB0 = EraseSector; |
mjr | 79:682ae3171a08 | 142 | FTFA->FCCOB1 = (address >> 16) & 0xFF; |
mjr | 79:682ae3171a08 | 143 | FTFA->FCCOB2 = (address >> 8) & 0xFF; |
mjr | 79:682ae3171a08 | 144 | FTFA->FCCOB3 = address & 0xFF; |
mjr | 79:682ae3171a08 | 145 | |
mjr | 79:682ae3171a08 | 146 | // execute |
mjr | 79:682ae3171a08 | 147 | iapExecAndWait(); |
mjr | 79:682ae3171a08 | 148 | |
mjr | 79:682ae3171a08 | 149 | // check the result |
mjr | 79:682ae3171a08 | 150 | return checkError(); |
mjr | 79:682ae3171a08 | 151 | } |
mjr | 79:682ae3171a08 | 152 | |
mjr | 79:682ae3171a08 | 153 | static FreescaleIAP::IAPCode verifySectorErased(int address) |
mjr | 79:682ae3171a08 | 154 | { |
mjr | 79:682ae3171a08 | 155 | // Always verify in whole sectors. The |
mjr | 79:682ae3171a08 | 156 | const unsigned int count = SECTOR_SIZE/4; |
mjr | 79:682ae3171a08 | 157 | |
mjr | 79:682ae3171a08 | 158 | #ifdef IAPDEBUG |
mjr | 79:682ae3171a08 | 159 | printf("IAP: Verify erased at %x, %d longwords (%d bytes)\r\n", address, count, count*4); |
mjr | 79:682ae3171a08 | 160 | #endif |
mjr | 79:682ae3171a08 | 161 | |
mjr | 79:682ae3171a08 | 162 | if (checkAlign(address)) |
mjr | 79:682ae3171a08 | 163 | return FreescaleIAP::AlignError; |
mjr | 79:682ae3171a08 | 164 | |
mjr | 79:682ae3171a08 | 165 | // clear errors |
mjr | 79:682ae3171a08 | 166 | clearErrors(); |
mjr | 79:682ae3171a08 | 167 | |
mjr | 79:682ae3171a08 | 168 | // Set up command |
mjr | 79:682ae3171a08 | 169 | FTFA->FCCOB0 = Read1s; |
mjr | 79:682ae3171a08 | 170 | FTFA->FCCOB1 = (address >> 16) & 0xFF; |
mjr | 79:682ae3171a08 | 171 | FTFA->FCCOB2 = (address >> 8) & 0xFF; |
mjr | 79:682ae3171a08 | 172 | FTFA->FCCOB3 = address & 0xFF; |
mjr | 79:682ae3171a08 | 173 | FTFA->FCCOB4 = (count >> 8) & 0xFF; |
mjr | 79:682ae3171a08 | 174 | FTFA->FCCOB5 = count & 0xFF; |
mjr | 79:682ae3171a08 | 175 | FTFA->FCCOB6 = 0; |
mjr | 79:682ae3171a08 | 176 | |
mjr | 79:682ae3171a08 | 177 | // execute |
mjr | 79:682ae3171a08 | 178 | iapExecAndWait(); |
mjr | 79:682ae3171a08 | 179 | |
mjr | 79:682ae3171a08 | 180 | // check the result |
mjr | 79:682ae3171a08 | 181 | FreescaleIAP::IAPCode retval = checkError(); |
mjr | 79:682ae3171a08 | 182 | if (retval == FreescaleIAP::RuntimeError) { |
mjr | 79:682ae3171a08 | 183 | #ifdef IAPDEBUG |
mjr | 79:682ae3171a08 | 184 | printf("IAP: Flash was not erased\r\n"); |
mjr | 79:682ae3171a08 | 185 | #endif |
mjr | 79:682ae3171a08 | 186 | return FreescaleIAP::EraseError; |
mjr | 79:682ae3171a08 | 187 | } |
mjr | 79:682ae3171a08 | 188 | return retval; |
mjr | 79:682ae3171a08 | 189 | } |
mjr | 79:682ae3171a08 | 190 | |
mjr | 79:682ae3171a08 | 191 | // Write one sector. This always writes a full sector, even if the |
mjr | 79:682ae3171a08 | 192 | // requested length is greater or less than the sector size: |
mjr | 79:682ae3171a08 | 193 | // |
mjr | 79:682ae3171a08 | 194 | // - if len > SECTOR_SIZE, we write the first SECTOR_SIZE bytes of the data |
mjr | 79:682ae3171a08 | 195 | // |
mjr | 79:682ae3171a08 | 196 | // - if len < SECTOR_SIZE, we write the data, then fill in the rest of the |
mjr | 79:682ae3171a08 | 197 | // sector with 0xFF bytes ('1' bits) |
mjr | 79:682ae3171a08 | 198 | // |
mjr | 79:682ae3171a08 | 199 | |
mjr | 79:682ae3171a08 | 200 | static FreescaleIAP::IAPCode writeSector(int address, const uint8_t *p, int len) |
mjr | 79:682ae3171a08 | 201 | { |
mjr | 79:682ae3171a08 | 202 | #ifdef IAPDEBUG |
mjr | 79:682ae3171a08 | 203 | printf("IAP: Writing sector at %x with length %d\r\n", address, len); |
mjr | 79:682ae3171a08 | 204 | #endif |
mjr | 79:682ae3171a08 | 205 | |
mjr | 79:682ae3171a08 | 206 | // program the sector, one longword (32 bits) at a time |
mjr | 79:682ae3171a08 | 207 | for (int ofs = 0 ; ofs < SECTOR_SIZE ; ofs += 4, address += 4, p += 4, len -= 4) |
mjr | 79:682ae3171a08 | 208 | { |
mjr | 79:682ae3171a08 | 209 | // clear errors |
mjr | 79:682ae3171a08 | 210 | clearErrors(); |
mjr | 79:682ae3171a08 | 211 | |
mjr | 79:682ae3171a08 | 212 | // Set up the command |
mjr | 79:682ae3171a08 | 213 | FTFA->FCCOB0 = ProgramLongword; |
mjr | 79:682ae3171a08 | 214 | FTFA->FCCOB1 = (address >> 16) & 0xFF; |
mjr | 79:682ae3171a08 | 215 | FTFA->FCCOB2 = (address >> 8) & 0xFF; |
mjr | 79:682ae3171a08 | 216 | FTFA->FCCOB3 = address & 0xFF; |
mjr | 79:682ae3171a08 | 217 | |
mjr | 79:682ae3171a08 | 218 | // Load the longword to write. If we're past the end of the source |
mjr | 79:682ae3171a08 | 219 | // data, write all '1' bits to the balance of the sector. |
mjr | 79:682ae3171a08 | 220 | FTFA->FCCOB4 = len > 3 ? p[3] : 0xFF; |
mjr | 79:682ae3171a08 | 221 | FTFA->FCCOB5 = len > 2 ? p[2] : 0xFF; |
mjr | 79:682ae3171a08 | 222 | FTFA->FCCOB6 = len > 1 ? p[1] : 0xFF; |
mjr | 79:682ae3171a08 | 223 | FTFA->FCCOB7 = len > 0 ? p[0] : 0xFF; |
mjr | 79:682ae3171a08 | 224 | |
mjr | 79:682ae3171a08 | 225 | // execute |
mjr | 79:682ae3171a08 | 226 | iapExecAndWait(); |
mjr | 79:682ae3171a08 | 227 | |
mjr | 79:682ae3171a08 | 228 | // check errors |
mjr | 79:682ae3171a08 | 229 | FreescaleIAP::IAPCode status = checkError(); |
mjr | 79:682ae3171a08 | 230 | if (status != FreescaleIAP::Success) |
mjr | 79:682ae3171a08 | 231 | return status; |
mjr | 79:682ae3171a08 | 232 | } |
mjr | 79:682ae3171a08 | 233 | |
mjr | 79:682ae3171a08 | 234 | // no problems |
mjr | 79:682ae3171a08 | 235 | return FreescaleIAP::Success; |
mjr | 79:682ae3171a08 | 236 | } |
mjr | 79:682ae3171a08 | 237 | |
mjr | 79:682ae3171a08 | 238 | // Program a block of memory into flash. |
mjr | 79:682ae3171a08 | 239 | FreescaleIAP::IAPCode FreescaleIAP::programFlash( |
mjr | 79:682ae3171a08 | 240 | int address, const void *src, unsigned int length) |
mjr | 79:682ae3171a08 | 241 | { |
mjr | 79:682ae3171a08 | 242 | #ifdef IAPDEBUG |
mjr | 79:682ae3171a08 | 243 | printf("IAP: Programming flash at %x with length %d\r\n", address, length); |
mjr | 79:682ae3171a08 | 244 | #endif |
mjr | 79:682ae3171a08 | 245 | |
mjr | 79:682ae3171a08 | 246 | // presume success |
mjr | 79:682ae3171a08 | 247 | FreescaleIAP::IAPCode status = FreescaleIAP::Success; |
mjr | 79:682ae3171a08 | 248 | |
mjr | 79:682ae3171a08 | 249 | // Show diagnostic LED colors while writing. I'm finally convinced this |
mjr | 79:682ae3171a08 | 250 | // is well and truly 100% reliable now, but I've been wrong before, so |
mjr | 79:682ae3171a08 | 251 | // we'll keep this for now. The idea is that if we freeze up, we'll at |
mjr | 79:682ae3171a08 | 252 | // least know which stage we're at from the last color displayed. |
mjr | 79:682ae3171a08 | 253 | extern void diagLED(int,int,int); |
mjr | 79:682ae3171a08 | 254 | |
mjr | 79:682ae3171a08 | 255 | // try a few times if we fail to verify |
mjr | 79:682ae3171a08 | 256 | for (int tries = 0 ; tries < 5 ; ++tries) |
mjr | 79:682ae3171a08 | 257 | { |
mjr | 79:682ae3171a08 | 258 | // Do the write one sector at a time |
mjr | 79:682ae3171a08 | 259 | int curaddr = address; |
mjr | 79:682ae3171a08 | 260 | const uint8_t *p = (const uint8_t *)src; |
mjr | 79:682ae3171a08 | 261 | int rem = (int)length; |
mjr | 79:682ae3171a08 | 262 | for ( ; rem > 0 ; curaddr += SECTOR_SIZE, p += SECTOR_SIZE, rem -= SECTOR_SIZE) |
mjr | 79:682ae3171a08 | 263 | { |
mjr | 79:682ae3171a08 | 264 | // erase the sector (red LED) |
mjr | 79:682ae3171a08 | 265 | diagLED(1, 0, 0); |
mjr | 79:682ae3171a08 | 266 | if ((status = eraseSector(curaddr)) != FreescaleIAP::Success) |
mjr | 79:682ae3171a08 | 267 | break; |
mjr | 79:682ae3171a08 | 268 | |
mjr | 79:682ae3171a08 | 269 | // verify that the sector is erased (yellow LED) |
mjr | 79:682ae3171a08 | 270 | diagLED(1, 1, 0); |
mjr | 79:682ae3171a08 | 271 | if ((status = verifySectorErased(curaddr)) != FreescaleIAP::Success) |
mjr | 79:682ae3171a08 | 272 | break; |
mjr | 79:682ae3171a08 | 273 | |
mjr | 79:682ae3171a08 | 274 | // write the data (white LED) |
mjr | 79:682ae3171a08 | 275 | diagLED(1, 1, 1); |
mjr | 79:682ae3171a08 | 276 | if ((status = writeSector(curaddr, p, rem)) != FreescaleIAP::Success) |
mjr | 79:682ae3171a08 | 277 | break; |
mjr | 79:682ae3171a08 | 278 | |
mjr | 79:682ae3171a08 | 279 | // back from write (purple LED) |
mjr | 79:682ae3171a08 | 280 | diagLED(1, 0, 1); |
mjr | 79:682ae3171a08 | 281 | } |
mjr | 79:682ae3171a08 | 282 | |
mjr | 79:682ae3171a08 | 283 | // if we didn't encounter an FTFA error, verify the write |
mjr | 79:682ae3171a08 | 284 | if (status == FreescaleIAP::Success) |
mjr | 79:682ae3171a08 | 285 | { |
mjr | 79:682ae3171a08 | 286 | // Verify the write. If it was successful, we're done. |
mjr | 79:682ae3171a08 | 287 | if (memcmp((void *)address, src, length) == 0) |
mjr | 80:94dc2946871b | 288 | { |
mjr | 80:94dc2946871b | 289 | // LEDs to green on success |
mjr | 80:94dc2946871b | 290 | diagLED(0, 1, 0); |
mjr | 79:682ae3171a08 | 291 | break; |
mjr | 80:94dc2946871b | 292 | } |
mjr | 79:682ae3171a08 | 293 | |
mjr | 79:682ae3171a08 | 294 | // We have a mismatch between the flash data and the source. |
mjr | 79:682ae3171a08 | 295 | // Flag the error and go back for another attempt. |
mjr | 79:682ae3171a08 | 296 | status = FreescaleIAP::VerifyError; |
mjr | 80:94dc2946871b | 297 | diagLED(1, 0, 0); |
mjr | 79:682ae3171a08 | 298 | } |
mjr | 79:682ae3171a08 | 299 | } |
mjr | 79:682ae3171a08 | 300 | |
mjr | 79:682ae3171a08 | 301 | // return the result |
mjr | 79:682ae3171a08 | 302 | return status; |
mjr | 79:682ae3171a08 | 303 | } |
mjr | 79:682ae3171a08 | 304 |