Mirror with some correction

Dependencies:   mbed FastIO FastPWM USBDevice

Committer:
mjr
Date:
Fri Mar 17 22:02:08 2017 +0000
Revision:
77:0b96f6867312
Parent:
76:7f5912b6340e
Child:
79:682ae3171a08
New memory pool management; keeping old ones as #ifdefs for now for reference.

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 77:0b96f6867312 18 // The KL25Z has an important restriction on flash writing that makes it
mjr 77:0b96f6867312 19 // very delicate. Specifically, the flash controller (FTFA) doesn't allow
mjr 77:0b96f6867312 20 // any read operations while a sector erase is in progress. This complicates
mjr 77:0b96f6867312 21 // things for a KL25Z app because all program code is stored in flash by
mjr 77:0b96f6867312 22 // default. This means that every instruction fetch is a flash read. The
mjr 77:0b96f6867312 23 // FTFA's response to a read while an erase is in progress is to fail the
mjr 77:0b96f6867312 24 // read. When the read is actually an instruction fetch, this results in
mjr 77:0b96f6867312 25 // CPU lockup. Making this even more complicated, the erase operation can
mjr 77:0b96f6867312 26 // only operate on a whole sector at a time, which takes on the order of
mjr 77:0b96f6867312 27 // milliseconds, which is a very long time for the CPU to go without any
mjr 77:0b96f6867312 28 // instruction fetches. Even if the code that initiates the erase is
mjr 77:0b96f6867312 29 // located in RAM and is very careful to loop within the RAM code block,
mjr 77:0b96f6867312 30 // any interrupt could take us out of the RAM loop and trigger a fetch
mjr 77:0b96f6867312 31 // on a flash location.
mjr 76:7f5912b6340e 32 //
mjr 76:7f5912b6340e 33 // We use two strategies to avoid flash fetches while we're working.
mjr 76:7f5912b6340e 34 // First, the code that performs all of the FTFA operations is written
mjr 76:7f5912b6340e 35 // in assembly, in a module AREA marked READWRITE. This forces the
mjr 76:7f5912b6340e 36 // linker to put the code in RAM. The code could otherwise just have
mjr 76:7f5912b6340e 37 // well been written in C++, but as far as I know there's no way to tell
mjr 76:7f5912b6340e 38 // the mbed C++ compiler to put code in RAM. Since the FTFA code is all
mjr 77:0b96f6867312 39 // in RAM, it doesn't by itself trigger any flash fetches as it executes,
mjr 77:0b96f6867312 40 // so we're left with interrupts as the only concern. Second, we explicitly
mjr 77:0b96f6867312 41 // disable all of the peripheral interrupts that we use anywhere in the
mjr 77:0b96f6867312 42 // program (USB, all the timers, GPIO ports, etc) via the NVIC. From
mjr 77:0b96f6867312 43 // testing, it's clear that disabling interrupts at the CPU level via
mjr 77:0b96f6867312 44 // __disable_irq() (or the equivalent assembly instruction CPSID I) isn't
mjr 77:0b96f6867312 45 // enough. We have to turn interrupts off at the peripheral (NVIC) level.
mjr 77:0b96f6867312 46 // I'm really not sure why this is required, since you'd think the CPSID I
mjr 77:0b96f6867312 47 // masking would be enough, but experimentally it's clearly not. This is
mjr 77:0b96f6867312 48 // a detail of ARM hardware architecture that I need to look into more,
mjr 77:0b96f6867312 49 // since it leaves me uneasy that there might be even more subtleties
mjr 77:0b96f6867312 50 // left to uncover. But at least things seem very stable after blocking
mjr 77:0b96f6867312 51 // interrupts at the NVIC level.
mjr 76:7f5912b6340e 52
mjr 2:c174f9ee414a 53 #include "FreescaleIAP.h"
mjr 2:c174f9ee414a 54
mjr 2:c174f9ee414a 55 //#define IAPDEBUG
mjr 76:7f5912b6340e 56
mjr 76:7f5912b6340e 57 // assembly interface
mjr 76:7f5912b6340e 58 extern "C" {
mjr 76:7f5912b6340e 59 void iapEraseSector(FTFA_Type *ftfa, uint32_t address);
mjr 76:7f5912b6340e 60 void iapProgramBlock(FTFA_Type *ftfa, uint32_t address, const void *src, uint32_t length);
mjr 76:7f5912b6340e 61 }
mjr 76:7f5912b6340e 62
mjr 76:7f5912b6340e 63
mjr 2:c174f9ee414a 64
mjr 2:c174f9ee414a 65 enum FCMD {
mjr 2:c174f9ee414a 66 Read1s = 0x01,
mjr 2:c174f9ee414a 67 ProgramCheck = 0x02,
mjr 2:c174f9ee414a 68 ReadResource = 0x03,
mjr 2:c174f9ee414a 69 ProgramLongword = 0x06,
mjr 2:c174f9ee414a 70 EraseSector = 0x09,
mjr 2:c174f9ee414a 71 Read1sBlock = 0x40,
mjr 2:c174f9ee414a 72 ReadOnce = 0x41,
mjr 2:c174f9ee414a 73 ProgramOnce = 0x43,
mjr 2:c174f9ee414a 74 EraseAll = 0x44,
mjr 2:c174f9ee414a 75 VerifyBackdoor = 0x45
mjr 2:c174f9ee414a 76 };
mjr 2:c174f9ee414a 77
mjr 2:c174f9ee414a 78
mjr 2:c174f9ee414a 79 /* Check if an error occured
mjr 2:c174f9ee414a 80 Returns error code or Success*/
mjr 76:7f5912b6340e 81 static IAPCode check_error(void)
mjr 76:7f5912b6340e 82 {
mjr 2:c174f9ee414a 83 if (FTFA->FSTAT & FTFA_FSTAT_FPVIOL_MASK) {
mjr 2:c174f9ee414a 84 #ifdef IAPDEBUG
mjr 2:c174f9ee414a 85 printf("IAP: Protection violation\r\n");
mjr 2:c174f9ee414a 86 #endif
mjr 2:c174f9ee414a 87 return ProtectionError;
mjr 2:c174f9ee414a 88 }
mjr 2:c174f9ee414a 89 if (FTFA->FSTAT & FTFA_FSTAT_ACCERR_MASK) {
mjr 2:c174f9ee414a 90 #ifdef IAPDEBUG
mjr 2:c174f9ee414a 91 printf("IAP: Flash access error\r\n");
mjr 2:c174f9ee414a 92 #endif
mjr 2:c174f9ee414a 93 return AccessError;
mjr 2:c174f9ee414a 94 }
mjr 2:c174f9ee414a 95 if (FTFA->FSTAT & FTFA_FSTAT_RDCOLERR_MASK) {
mjr 2:c174f9ee414a 96 #ifdef IAPDEBUG
mjr 2:c174f9ee414a 97 printf("IAP: Collision error\r\n");
mjr 2:c174f9ee414a 98 #endif
mjr 2:c174f9ee414a 99 return CollisionError;
mjr 2:c174f9ee414a 100 }
mjr 2:c174f9ee414a 101 if (FTFA->FSTAT & FTFA_FSTAT_MGSTAT0_MASK) {
mjr 2:c174f9ee414a 102 #ifdef IAPDEBUG
mjr 2:c174f9ee414a 103 printf("IAP: Runtime error\r\n");
mjr 2:c174f9ee414a 104 #endif
mjr 2:c174f9ee414a 105 return RuntimeError;
mjr 2:c174f9ee414a 106 }
mjr 2:c174f9ee414a 107 #ifdef IAPDEBUG
mjr 2:c174f9ee414a 108 printf("IAP: No error reported\r\n");
mjr 2:c174f9ee414a 109 #endif
mjr 2:c174f9ee414a 110 return Success;
mjr 76:7f5912b6340e 111 }
mjr 76:7f5912b6340e 112
mjr 76:7f5912b6340e 113 IAPCode FreescaleIAP::program_flash(int address, const void *src, unsigned int length)
mjr 76:7f5912b6340e 114 {
mjr 76:7f5912b6340e 115 #ifdef IAPDEBUG
mjr 76:7f5912b6340e 116 printf("IAP: Programming flash at %x with length %d\r\n", address, length);
mjr 76:7f5912b6340e 117 #endif
mjr 77:0b96f6867312 118
mjr 76:7f5912b6340e 119 // presume success
mjr 76:7f5912b6340e 120 IAPCode status = Success;
mjr 76:7f5912b6340e 121
mjr 76:7f5912b6340e 122 // I'm not 100% convinced this is 100% reliable yet. So let's show
mjr 76:7f5912b6340e 123 // some diagnostic lights while we're working. If anyone sees any
mjr 76:7f5912b6340e 124 // freezes, the lights that are left on at the freeze will tell us
mjr 76:7f5912b6340e 125 // which step is crashing.
mjr 76:7f5912b6340e 126 extern void diagLED(int,int,int);
mjr 76:7f5912b6340e 127
mjr 76:7f5912b6340e 128 // Erase the sector(s) covered by the write. Before writing, we must
mjr 76:7f5912b6340e 129 // erase each sector that we're going to touch on the write.
mjr 76:7f5912b6340e 130 for (uint32_t ofs = 0 ; ofs < length ; ofs += SECTOR_SIZE)
mjr 76:7f5912b6340e 131 {
mjr 76:7f5912b6340e 132 // Show RED on the first sector, GREEN on second, BLUE on third. Each
mjr 76:7f5912b6340e 133 // sector is 1K, so I don't think we'll need more than 3 for the
mjr 76:7f5912b6340e 134 // foreseeable future. (RAM on the KL25Z is so tight that it will
mjr 76:7f5912b6340e 135 // probably stop us from adding enough features to require more
mjr 76:7f5912b6340e 136 // configuration variables than 3K worth.)
mjr 76:7f5912b6340e 137 diagLED(ofs/SECTOR_SIZE == 0, ofs/SECTOR_SIZE == 1, ofs/SECTOR_SIZE == 2);
mjr 76:7f5912b6340e 138
mjr 76:7f5912b6340e 139 // erase the sector
mjr 76:7f5912b6340e 140 iapEraseSector(FTFA, address + ofs);
mjr 76:7f5912b6340e 141 }
mjr 76:7f5912b6340e 142
mjr 76:7f5912b6340e 143 // If the erase was successful, write the data.
mjr 76:7f5912b6340e 144 if ((status = check_error()) == Success)
mjr 76:7f5912b6340e 145 {
mjr 76:7f5912b6340e 146 // show cyan while the write is in progress
mjr 76:7f5912b6340e 147 diagLED(0, 1, 1);
mjr 76:7f5912b6340e 148
mjr 76:7f5912b6340e 149 // do the write
mjr 76:7f5912b6340e 150 iapProgramBlock(FTFA, address, src, length);
mjr 76:7f5912b6340e 151
mjr 77:0b96f6867312 152 // purple when done
mjr 77:0b96f6867312 153 diagLED(1, 0, 1);
mjr 76:7f5912b6340e 154
mjr 76:7f5912b6340e 155 // check again for errors
mjr 76:7f5912b6340e 156 status = check_error();
mjr 76:7f5912b6340e 157 }
mjr 76:7f5912b6340e 158
mjr 76:7f5912b6340e 159 // return the result
mjr 76:7f5912b6340e 160 return status;
mjr 76:7f5912b6340e 161 }
mjr 76:7f5912b6340e 162
mjr 76:7f5912b6340e 163 uint32_t FreescaleIAP::flash_size(void)
mjr 76:7f5912b6340e 164 {
mjr 76:7f5912b6340e 165 uint32_t retval = (SIM->FCFG2 & 0x7F000000u) >> (24-13);
mjr 77:0b96f6867312 166 if (SIM->FCFG2 & (1<<23)) // Possible second flash bank
mjr 76:7f5912b6340e 167 retval += (SIM->FCFG2 & 0x007F0000u) >> (16-13);
mjr 76:7f5912b6340e 168 return retval;
mjr 76:7f5912b6340e 169 }
mjr 76:7f5912b6340e 170
mjr 76:7f5912b6340e 171 /* Check if no flash boundary is violated
mjr 76:7f5912b6340e 172 Returns true on violation */
mjr 76:7f5912b6340e 173 bool check_boundary(int address, unsigned int length)
mjr 76:7f5912b6340e 174 {
mjr 76:7f5912b6340e 175 int temp = (address+length - 1) / SECTOR_SIZE;
mjr 76:7f5912b6340e 176 address /= SECTOR_SIZE;
mjr 76:7f5912b6340e 177 bool retval = (address != temp);
mjr 76:7f5912b6340e 178 #ifdef IAPDEBUG
mjr 76:7f5912b6340e 179 if (retval)
mjr 76:7f5912b6340e 180 printf("IAP: Boundary violation\r\n");
mjr 76:7f5912b6340e 181 #endif
mjr 76:7f5912b6340e 182 return retval;
mjr 76:7f5912b6340e 183 }
mjr 76:7f5912b6340e 184
mjr 76:7f5912b6340e 185 /* Check if address is correctly aligned
mjr 76:7f5912b6340e 186 Returns true on violation */
mjr 76:7f5912b6340e 187 bool check_align(int address)
mjr 76:7f5912b6340e 188 {
mjr 76:7f5912b6340e 189 bool retval = address & 0x03;
mjr 76:7f5912b6340e 190 #ifdef IAPDEBUG
mjr 76:7f5912b6340e 191 if (retval)
mjr 76:7f5912b6340e 192 printf("IAP: Alignment violation\r\n");
mjr 76:7f5912b6340e 193 #endif
mjr 76:7f5912b6340e 194 return retval;
mjr 76:7f5912b6340e 195 }
mjr 76:7f5912b6340e 196