Actual erase/write to flash is the 'easy part'; code below. The hard part is setting up the tools to understand the bootloader/application-space setup, determining 'validness' of application image, and other such implementation details. One thing to keep in mind: You can't erase/write the 'bank' you're running in! For applications that truly 'ping pong' between two half-flash-sized full memory code images, the latest 1.2 (and higher) silicon implements a fairly robust flash control mechanism for updating the 'opposite bank' with hooks to recover failed attempts. For the case with 16K 'low boot', rest 'APP' -- that matches my world, and for that the IAR linker provides some help in that I allow it to link the bootloader code to RAM addresses and its startup copies it all out there and runs from there, freeing any concern over Flash bank execution restrictions. I use the IAR linker also to fill unused Flash space with SVC 0xDF interrupts, and place a CRC32 at the end which I check using the Kinetis CRC module.
--ERGII
static int fnFlashNow(uint8_t ucCommand, uint32_t ptrWord, uint32_t ulWord)
{
do{
}while (!(FTFL_FSTAT & FTFL_FSTAT_CCIF_MASK)); // wait for previous commands to complete
if (FTFL_FSTAT & (FTFL_FSTAT_ACCERR_MASK | FTFL_FSTAT_FPVIOL_MASK)) { // check for errors in previous command
FTFL_FSTAT = (FTFL_FSTAT_ACCERR_MASK | FTFL_FSTAT_FPVIOL_MASK); // clear old errors
}
switch (FTFL_FCCOB0 = ucCommand) { // enter the command sequence
case FCMD_ERASE_ALL_BLOCKS: // single command word required with the erase all blocks command
break;
case FCMD_SWAP_CONTROL:
FTFL_FCCOB6 = 0xFF; //Clear these status bytes, in case of fault
FTFL_FCCOB7 = 0xFF;
case FCMD_PROGRAM_SECTION:
if( ucCommand == FCMD_PROGRAM_SECTION )
ulWord >>= 3; //Convert to dual-dword count
FTFL_FCCOB4 = (u8_t)(ulWord >> 8);
FTFL_FCCOB5 = (u8_t)(ulWord);
case FCMD_ERASE_FLASH_SECTOR:
FTFL_FCCOB1 = (u8_t)(((CAST_POINTER_ARITHMETIC)ptrWord) >> 16);
FTFL_FCCOB2 = (u8_t)(((CAST_POINTER_ARITHMETIC)ptrWord) >> 8);
FTFL_FCCOB3 = (u8_t)((CAST_POINTER_ARITHMETIC)ptrWord);
break;
}
Disable_Interrupt(); // protect this region from interrupts
FTFL_FSTAT = FTFL_FSTAT_CCIF_MASK; // launch the command - this clears the FTFL_STAT_CCIF flag (register is FTFL_FSTAT)
while (!(FTFL_FSTAT & FTFL_FSTAT_CCIF_MASK)) {} // wait for the command to terminate
return (FTFL_FSTAT & (FTFL_FSTAT_ACCERR_MASK | FTFL_FSTAT_FPVIOL_MASK
| FTFL_FSTAT_MGSTAT0_MASK)); // if there was an error this will be non-zero
}
And a block copy of one memory area to flash is just:
bool_t fnCopyBoot( uint32_t srcptr, uint32_t dstptr )
{
uint16_t file_length = APP_START; //This example moves a whole bootloader image size
uint16_t usBlockSize = BLOCK_SIZE; //This is 2K, of course
while (file_length) {
if (file_length < BLOCK_SIZE) {
usBlockSize = (u16_t)file_length; // last block smaller than full block size
}
Memcpy_long((uint32_t *)&FlashRAM, (uint32_t *)srcptr, (uint32_t)usBlockSize); //Copy current code to burn-RAM
if( fnFlashNow(FCMD_ERASE_FLASH_SECTOR, dstptr, usBlockSize) ) {
return FALSE; // error
}
fnFlashNow(FCMD_PROGRAM_SECTION, dstptr, usBlockSize);
srcptr += usBlockSize;
dstptr += usBlockSize;
file_length -= usBlockSize;
}
return TRUE;
}