Mirror with some correction

Dependencies:   mbed FastIO FastPWM USBDevice

Committer:
mjr
Date:
Fri Feb 03 20:50:02 2017 +0000
Revision:
76:7f5912b6340e
Parent:
60:f38da020aa13
Child:
77:0b96f6867312
Rework flash driver to make it truly stable (hopefully to 100% reliability); host-loaded configuration; performance improvements; more performance diagnostics.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
mjr 76:7f5912b6340e 1 // FreescaleIAP, private version
mjr 76:7f5912b6340e 2 //
mjr 76:7f5912b6340e 3 // This is a heavily modified version of Erik Olieman's FreescaleIAP, a
mjr 76:7f5912b6340e 4 // flash memory writer for Freescale boards. This version is adapted to
mjr 76:7f5912b6340e 5 // the special needs of the KL25Z.
mjr 76:7f5912b6340e 6 //
mjr 76:7f5912b6340e 7 // Simplifications:
mjr 76:7f5912b6340e 8 //
mjr 76:7f5912b6340e 9 // Unlike EO's original version, this version combines erase and write
mjr 76:7f5912b6340e 10 // into a single opreation, so the caller can simply give us a buffer
mjr 76:7f5912b6340e 11 // and a location, and we'll write it, including the erase prep. We
mjr 76:7f5912b6340e 12 // don't need to be able to separate the operations, so the combined
mjr 76:7f5912b6340e 13 // interface is simpler at the API level and also lets us do all of the
mjr 76:7f5912b6340e 14 // interrupt masking in one place (see below).
mjr 76:7f5912b6340e 15 //
mjr 76:7f5912b6340e 16 // Stability improvements:
mjr 76:7f5912b6340e 17 //
mjr 76:7f5912b6340e 18 // The KL25Z has severe restrictions on flash writing that make it very
mjr 76:7f5912b6340e 19 // delicate. The key restriction is that the flash controller (FTFA)
mjr 76:7f5912b6340e 20 // doesn't allow any read operations while a sector erase is in progress.
mjr 76:7f5912b6340e 21 // The reason this complicates things is that all program code is stored
mjr 76:7f5912b6340e 22 // in flash by default. This means that every instruction fetch is a
mjr 76:7f5912b6340e 23 // flash read operation. The FTFA's response to a read while an erase is
mjr 76:7f5912b6340e 24 // in progress is to fail the read and return arbitrary data. When the
mjr 76:7f5912b6340e 25 // read is actually an instruction fetch, this results in the CPU trying
mjr 76:7f5912b6340e 26 // to execute random garbage, which virtually always crashes the program
mjr 76:7f5912b6340e 27 // and freezes the CPU. Making this even more complicated, the erase
mjr 76:7f5912b6340e 28 // operation runs a whole sector at a time, which takes a very long time
mjr 76:7f5912b6340e 29 // in CPU terms, on the order of milliseconds. Even if the code that
mjr 76:7f5912b6340e 30 // initiates the erase is very careful to loop without branching to any
mjr 76:7f5912b6340e 31 // flash locations, it's still a long time to go without an interrupt
mjr 76:7f5912b6340e 32 // occurring
mjr 76:7f5912b6340e 33 //
mjr 76:7f5912b6340e 34 // We use two strategies to avoid flash fetches while we're working.
mjr 76:7f5912b6340e 35 // First, the code that performs all of the FTFA operations is written
mjr 76:7f5912b6340e 36 // in assembly, in a module AREA marked READWRITE. This forces the
mjr 76:7f5912b6340e 37 // linker to put the code in RAM. The code could otherwise just have
mjr 76:7f5912b6340e 38 // well been written in C++, but as far as I know there's no way to tell
mjr 76:7f5912b6340e 39 // the mbed C++ compiler to put code in RAM. Since the FTFA code is all
mjr 76:7f5912b6340e 40 // in RAM, it doesn't trigger any flash fetches as it executes. Second,
mjr 76:7f5912b6340e 41 // we explicitly disable all of the peripheral interrupts that we use
mjr 76:7f5912b6340e 42 // anywhere in the program (USB, all the timers, etc) via the NVIC. It
mjr 76:7f5912b6340e 43 // isn't sufficient to disable interrupts with __disable_irq() or the
mjr 76:7f5912b6340e 44 // equivalent assembly instruction CPSID I; we have to turn them off at
mjr 76:7f5912b6340e 45 // the NVIC level. My understanding of ARM system architecture isn't
mjr 76:7f5912b6340e 46 // detailed enough to know why this is required, but experimentally it
mjr 76:7f5912b6340e 47 // definitely seems to be needed.
mjr 76:7f5912b6340e 48
mjr 2:c174f9ee414a 49 #include "FreescaleIAP.h"
mjr 2:c174f9ee414a 50
mjr 2:c174f9ee414a 51 //#define IAPDEBUG
mjr 76:7f5912b6340e 52
mjr 76:7f5912b6340e 53 // assembly interface
mjr 76:7f5912b6340e 54 extern "C" {
mjr 76:7f5912b6340e 55 void iapEraseSector(FTFA_Type *ftfa, uint32_t address);
mjr 76:7f5912b6340e 56 void iapProgramBlock(FTFA_Type *ftfa, uint32_t address, const void *src, uint32_t length);
mjr 76:7f5912b6340e 57 }
mjr 76:7f5912b6340e 58
mjr 76:7f5912b6340e 59
mjr 2:c174f9ee414a 60
mjr 2:c174f9ee414a 61 enum FCMD {
mjr 2:c174f9ee414a 62 Read1s = 0x01,
mjr 2:c174f9ee414a 63 ProgramCheck = 0x02,
mjr 2:c174f9ee414a 64 ReadResource = 0x03,
mjr 2:c174f9ee414a 65 ProgramLongword = 0x06,
mjr 2:c174f9ee414a 66 EraseSector = 0x09,
mjr 2:c174f9ee414a 67 Read1sBlock = 0x40,
mjr 2:c174f9ee414a 68 ReadOnce = 0x41,
mjr 2:c174f9ee414a 69 ProgramOnce = 0x43,
mjr 2:c174f9ee414a 70 EraseAll = 0x44,
mjr 2:c174f9ee414a 71 VerifyBackdoor = 0x45
mjr 2:c174f9ee414a 72 };
mjr 2:c174f9ee414a 73
mjr 2:c174f9ee414a 74
mjr 2:c174f9ee414a 75 /* Check if an error occured
mjr 2:c174f9ee414a 76 Returns error code or Success*/
mjr 76:7f5912b6340e 77 static IAPCode check_error(void)
mjr 76:7f5912b6340e 78 {
mjr 2:c174f9ee414a 79 if (FTFA->FSTAT & FTFA_FSTAT_FPVIOL_MASK) {
mjr 2:c174f9ee414a 80 #ifdef IAPDEBUG
mjr 2:c174f9ee414a 81 printf("IAP: Protection violation\r\n");
mjr 2:c174f9ee414a 82 #endif
mjr 2:c174f9ee414a 83 return ProtectionError;
mjr 2:c174f9ee414a 84 }
mjr 2:c174f9ee414a 85 if (FTFA->FSTAT & FTFA_FSTAT_ACCERR_MASK) {
mjr 2:c174f9ee414a 86 #ifdef IAPDEBUG
mjr 2:c174f9ee414a 87 printf("IAP: Flash access error\r\n");
mjr 2:c174f9ee414a 88 #endif
mjr 2:c174f9ee414a 89 return AccessError;
mjr 2:c174f9ee414a 90 }
mjr 2:c174f9ee414a 91 if (FTFA->FSTAT & FTFA_FSTAT_RDCOLERR_MASK) {
mjr 2:c174f9ee414a 92 #ifdef IAPDEBUG
mjr 2:c174f9ee414a 93 printf("IAP: Collision error\r\n");
mjr 2:c174f9ee414a 94 #endif
mjr 2:c174f9ee414a 95 return CollisionError;
mjr 2:c174f9ee414a 96 }
mjr 2:c174f9ee414a 97 if (FTFA->FSTAT & FTFA_FSTAT_MGSTAT0_MASK) {
mjr 2:c174f9ee414a 98 #ifdef IAPDEBUG
mjr 2:c174f9ee414a 99 printf("IAP: Runtime error\r\n");
mjr 2:c174f9ee414a 100 #endif
mjr 2:c174f9ee414a 101 return RuntimeError;
mjr 2:c174f9ee414a 102 }
mjr 2:c174f9ee414a 103 #ifdef IAPDEBUG
mjr 2:c174f9ee414a 104 printf("IAP: No error reported\r\n");
mjr 2:c174f9ee414a 105 #endif
mjr 2:c174f9ee414a 106 return Success;
mjr 76:7f5912b6340e 107 }
mjr 76:7f5912b6340e 108
mjr 76:7f5912b6340e 109 IAPCode FreescaleIAP::program_flash(int address, const void *src, unsigned int length)
mjr 76:7f5912b6340e 110 {
mjr 76:7f5912b6340e 111 #ifdef IAPDEBUG
mjr 76:7f5912b6340e 112 printf("IAP: Programming flash at %x with length %d\r\n", address, length);
mjr 76:7f5912b6340e 113 #endif
mjr 76:7f5912b6340e 114
mjr 76:7f5912b6340e 115 // Disable peripheral IRQs. Empirically, this seems to be vital to
mjr 76:7f5912b6340e 116 // getting the writing process (especially the erase step) to work
mjr 76:7f5912b6340e 117 // reliably. Even with the CPU interrupt mask off (CPSID I in the
mjr 76:7f5912b6340e 118 // assembly), it appears that peripheral interrupts will
mjr 76:7f5912b6340e 119 NVIC_DisableIRQ(PIT_IRQn);
mjr 76:7f5912b6340e 120 NVIC_DisableIRQ(I2C0_IRQn);
mjr 76:7f5912b6340e 121 NVIC_DisableIRQ(I2C1_IRQn);
mjr 76:7f5912b6340e 122 NVIC_DisableIRQ(PORTA_IRQn);
mjr 76:7f5912b6340e 123 NVIC_DisableIRQ(PORTD_IRQn);
mjr 76:7f5912b6340e 124 NVIC_DisableIRQ(USB0_IRQn);
mjr 76:7f5912b6340e 125 NVIC_DisableIRQ(TPM0_IRQn);
mjr 76:7f5912b6340e 126 NVIC_DisableIRQ(TPM1_IRQn);
mjr 76:7f5912b6340e 127 NVIC_DisableIRQ(TPM2_IRQn);
mjr 76:7f5912b6340e 128 NVIC_DisableIRQ(RTC_IRQn);
mjr 76:7f5912b6340e 129 NVIC_DisableIRQ(RTC_Seconds_IRQn);
mjr 76:7f5912b6340e 130 NVIC_DisableIRQ(LPTimer_IRQn);
mjr 76:7f5912b6340e 131
mjr 76:7f5912b6340e 132 // presume success
mjr 76:7f5912b6340e 133 IAPCode status = Success;
mjr 76:7f5912b6340e 134
mjr 76:7f5912b6340e 135 // I'm not 100% convinced this is 100% reliable yet. So let's show
mjr 76:7f5912b6340e 136 // some diagnostic lights while we're working. If anyone sees any
mjr 76:7f5912b6340e 137 // freezes, the lights that are left on at the freeze will tell us
mjr 76:7f5912b6340e 138 // which step is crashing.
mjr 76:7f5912b6340e 139 extern void diagLED(int,int,int);
mjr 76:7f5912b6340e 140
mjr 76:7f5912b6340e 141 // Erase the sector(s) covered by the write. Before writing, we must
mjr 76:7f5912b6340e 142 // erase each sector that we're going to touch on the write.
mjr 76:7f5912b6340e 143 for (uint32_t ofs = 0 ; ofs < length ; ofs += SECTOR_SIZE)
mjr 76:7f5912b6340e 144 {
mjr 76:7f5912b6340e 145 // Show RED on the first sector, GREEN on second, BLUE on third. Each
mjr 76:7f5912b6340e 146 // sector is 1K, so I don't think we'll need more than 3 for the
mjr 76:7f5912b6340e 147 // foreseeable future. (RAM on the KL25Z is so tight that it will
mjr 76:7f5912b6340e 148 // probably stop us from adding enough features to require more
mjr 76:7f5912b6340e 149 // configuration variables than 3K worth.)
mjr 76:7f5912b6340e 150 diagLED(ofs/SECTOR_SIZE == 0, ofs/SECTOR_SIZE == 1, ofs/SECTOR_SIZE == 2);
mjr 76:7f5912b6340e 151
mjr 76:7f5912b6340e 152 // erase the sector
mjr 76:7f5912b6340e 153 iapEraseSector(FTFA, address + ofs);
mjr 76:7f5912b6340e 154 }
mjr 76:7f5912b6340e 155
mjr 76:7f5912b6340e 156 // If the erase was successful, write the data.
mjr 76:7f5912b6340e 157 if ((status = check_error()) == Success)
mjr 76:7f5912b6340e 158 {
mjr 76:7f5912b6340e 159 // show cyan while the write is in progress
mjr 76:7f5912b6340e 160 diagLED(0, 1, 1);
mjr 76:7f5912b6340e 161
mjr 76:7f5912b6340e 162 // do the write
mjr 76:7f5912b6340e 163 iapProgramBlock(FTFA, address, src, length);
mjr 76:7f5912b6340e 164
mjr 76:7f5912b6340e 165 // show white when the write completes
mjr 76:7f5912b6340e 166 diagLED(1, 1, 1);
mjr 76:7f5912b6340e 167
mjr 76:7f5912b6340e 168 // check again for errors
mjr 76:7f5912b6340e 169 status = check_error();
mjr 76:7f5912b6340e 170 }
mjr 76:7f5912b6340e 171
mjr 76:7f5912b6340e 172 // restore peripheral IRQs
mjr 76:7f5912b6340e 173 NVIC_EnableIRQ(PIT_IRQn);
mjr 76:7f5912b6340e 174 NVIC_EnableIRQ(I2C0_IRQn);
mjr 76:7f5912b6340e 175 NVIC_EnableIRQ(I2C1_IRQn);
mjr 76:7f5912b6340e 176 NVIC_EnableIRQ(PORTA_IRQn);
mjr 76:7f5912b6340e 177 NVIC_EnableIRQ(PORTD_IRQn);
mjr 76:7f5912b6340e 178 NVIC_EnableIRQ(USB0_IRQn);
mjr 76:7f5912b6340e 179 NVIC_EnableIRQ(TPM0_IRQn);
mjr 76:7f5912b6340e 180 NVIC_EnableIRQ(TPM1_IRQn);
mjr 76:7f5912b6340e 181 NVIC_EnableIRQ(TPM2_IRQn);
mjr 76:7f5912b6340e 182 NVIC_EnableIRQ(RTC_IRQn);
mjr 76:7f5912b6340e 183 NVIC_EnableIRQ(RTC_Seconds_IRQn);
mjr 76:7f5912b6340e 184 NVIC_EnableIRQ(LPTimer_IRQn);
mjr 76:7f5912b6340e 185
mjr 76:7f5912b6340e 186 // return the result
mjr 76:7f5912b6340e 187 return status;
mjr 76:7f5912b6340e 188 }
mjr 76:7f5912b6340e 189
mjr 76:7f5912b6340e 190 uint32_t FreescaleIAP::flash_size(void)
mjr 76:7f5912b6340e 191 {
mjr 76:7f5912b6340e 192 uint32_t retval = (SIM->FCFG2 & 0x7F000000u) >> (24-13);
mjr 76:7f5912b6340e 193 if (SIM->FCFG2 & (1<<23)) //Possible second flash bank
mjr 76:7f5912b6340e 194 retval += (SIM->FCFG2 & 0x007F0000u) >> (16-13);
mjr 76:7f5912b6340e 195 return retval;
mjr 76:7f5912b6340e 196 }
mjr 76:7f5912b6340e 197
mjr 76:7f5912b6340e 198 /* Check if no flash boundary is violated
mjr 76:7f5912b6340e 199 Returns true on violation */
mjr 76:7f5912b6340e 200 bool check_boundary(int address, unsigned int length)
mjr 76:7f5912b6340e 201 {
mjr 76:7f5912b6340e 202 int temp = (address+length - 1) / SECTOR_SIZE;
mjr 76:7f5912b6340e 203 address /= SECTOR_SIZE;
mjr 76:7f5912b6340e 204 bool retval = (address != temp);
mjr 76:7f5912b6340e 205 #ifdef IAPDEBUG
mjr 76:7f5912b6340e 206 if (retval)
mjr 76:7f5912b6340e 207 printf("IAP: Boundary violation\r\n");
mjr 76:7f5912b6340e 208 #endif
mjr 76:7f5912b6340e 209 return retval;
mjr 76:7f5912b6340e 210 }
mjr 76:7f5912b6340e 211
mjr 76:7f5912b6340e 212 /* Check if address is correctly aligned
mjr 76:7f5912b6340e 213 Returns true on violation */
mjr 76:7f5912b6340e 214 bool check_align(int address)
mjr 76:7f5912b6340e 215 {
mjr 76:7f5912b6340e 216 bool retval = address & 0x03;
mjr 76:7f5912b6340e 217 #ifdef IAPDEBUG
mjr 76:7f5912b6340e 218 if (retval)
mjr 76:7f5912b6340e 219 printf("IAP: Alignment violation\r\n");
mjr 76:7f5912b6340e 220 #endif
mjr 76:7f5912b6340e 221 return retval;
mjr 76:7f5912b6340e 222 }
mjr 76:7f5912b6340e 223