Hi
I don't know why there is a reset in your case but the Swap Block operation is a bit tricker that the erase and programming commands.
Below is the swap routine used in the uTasker project as reference - note that the REPORT_SWAP_STATUS is written to CCOB4 as a long word (with all other bits set to 1 according to the recommendations), so you may like to try using such accesses in case you are presently using byte accesses.
The Flash swap mechanism is also simulated in the uTasker K22 simulator, which makes any code or behavior analysis easier if needed.
extern int fnSwapMemory(int iCheck)
{
#define FLASH_SWAP_INDICATOR_ADDRESS ((FLASH_START_ADDRESS + (SIZE_OF_FLASH/2)) - 32) // final sector in the first half of flash memory used as flash swap indicator
unsigned long ulCommand;
while (1) {
ulCommand = ((SWAP_CONTROL_CODE_REPORT_SWAP_STATUS << 24) | 0x00ffffff); // note that the unused bytes in the command are set to 0xff so that it is clear whether they are changed by the operation (failed operatios may otherwise not be detectable)
if (fnFlashNow(FCMD_SWAP, (unsigned long *)FLASH_SWAP_INDICATOR_ADDRESS, &ulCommand) != 0) { // get the swap state
return SWAP_COMMAND_FAILURE; // error
}
switch ((unsigned char)(ulCommand >> 16)) { // switch on current swap mode
case CURRENT_SWAP_MODE_UNINITIALISED:
{
int iPhrases = 0;
unsigned long *ptrSwapIndicator = (unsigned long *)FLASH_SWAP_INDICATOR_ADDRESS;
if (iCheck != 0) { // if checking present state
return SWAP_STATE_UNINITIALISED; // uninitialised
}
while (iPhrases++ < ((FLASH_ROW_SIZE/sizeof(unsigned long)) * 2)) { // for each of the two phrases of each block containing the swap indicator
if (*(unsigned long *)fnGetFlashAdd((unsigned char *)ptrSwapIndicator) != 0xffffffff) {
fnDebugMsg("Cleaning swap indicator sector\r\n");
if ((fnFlashNow(FCMD_ERASE_FLASH_SECTOR, ptrSwapIndicator, (unsigned long)0)) != 0) { // erase the sector
return SWAP_ERASE_FAILURE;
}
}
if (iPhrases == (FLASH_ROW_SIZE/sizeof(unsigned long))) { // after checking the two phrases in the first block move to the second block
ptrSwapIndicator = (unsigned long *)(FLASH_SWAP_INDICATOR_ADDRESS + (SIZE_OF_FLASH/2)); // location in the second block
}
else {
ptrSwapIndicator++; // move to the next long word
}
}
ulCommand = ((SWAP_CONTROL_CODE_INITIALISE_SWAP_SYSTEM << 24) | 0x00ffffff); // set the flash swap indicator address to initialise the swap mechanism (this address is programmed to IFR swap memory and 0xff00 programmed to the swap indicator address in the first block)
if (fnFlashNow(FCMD_SWAP, (unsigned long *)FLASH_SWAP_INDICATOR_ADDRESS, &ulCommand) != 0) { // start by initialising the swap process
return SWAP_COMMAND_FAILURE;
}
while (FTFL_FCCOB5 == CURRENT_SWAP_MODE_UNINITIALISED) {}// the current swap mode may take a little time to complete so wait until the new state is indicated
}
break;
case CURRENT_SWAP_MODE_READY:
ulCommand = ((SWAP_CONTROL_CODE_SET_SWAP_IN_UPDATE_STATE << 24) | 0x00ffffff);
if (fnFlashNow(FCMD_SWAP, (unsigned long *)FLASH_SWAP_INDICATOR_ADDRESS, &ulCommand) != 0) {
return SWAP_COMMAND_FAILURE; // error
}
while (FTFL_FCCOB5 == CURRENT_SWAP_MODE_READY) {} // the current swap mode may take a little time to complete so wait until the new state is indicated
break;
case CURRENT_SWAP_MODE_UPDATE:
if (iCheck != 0) { // checking and not swapping
if ((unsigned char)(ulCommand >> 8) != 0) { // check the active block
return SWAP_STATE_USING_1; // block 1 is being used
}
else {
return SWAP_STATE_USING_0; // block 0 is being used
}
}
else {
// We are performing a swap from one active block to another
// - this requires erasing the swap indicator of the non-active block
//
if ((fnFlashNow(FCMD_ERASE_FLASH_SECTOR, (unsigned long *)(FLASH_SWAP_INDICATOR_ADDRESS + (SIZE_OF_FLASH/2)), (unsigned long)0)) != 0) { // erase the sector
return SWAP_ERASE_FAILURE;
}
}
// Fall through intentionally
//
case CURRENT_SWAP_MODE_UPDATE_ERASED:
ulCommand = ((SWAP_CONTROL_CODE_SET_SWAP_IN_COMPLETE_STATE << 24) | 0x00ffffff);
if (fnFlashNow(FCMD_SWAP, (unsigned long *)FLASH_SWAP_INDICATOR_ADDRESS, &ulCommand) != 0) {
return SWAP_COMMAND_FAILURE;
}
while (FTFL_FCCOB5 != CURRENT_SWAP_MODE_COMPLETE) {} // the current swap mode may take a little time to complete so wait until the new state is indicated
// Fall through intentionally
//
case CURRENT_SWAP_MODE_COMPLETE:
return SWAP_STATE_SWAPPED; // swap has completed - a reset is required to effect the new operation
default:
break; // unexpected - continue until a valid state is returned
}
}
return 0;
}There is a reference solution for a swap block based loader here (on FRDM-K64F but the same code works on all K devices with swap block support): http://www.utasker.com/kinetis/FRDM-K64F.html#SWAP
and additional dicussion with some technical details at https://community.freescale.com/message/586326#586326
The uTasker Serial Loader includes a swap block option which handles the operation, and recovery in case fo a reset/power cycle during the swap, based on the previous routine as follows [it is called with parameter 1 to check after each reset and with 0 to perform the swap]:
extern void fnHandleSwap(int iCheck)
{
int iResut = fnSwapMemory(iCheck);
fnDebugMsg("\r\nSwap ");
switch (iResut) {
case SWAP_STATE_UNINITIALISED:
fnDebugMsg("uninitialised");
break;
case SWAP_STATE_SWAPPED: // expected only after commanding a swap
fnDebugMsg("OK");
if (iCheck == 0) {
fnDebugMsg(" - resetting...\r\n");
uTaskerMonoTimer(OWN_TASK, (DELAY_LIMIT)(1 * SEC), T_RESET); // reset after a short delay
}
break;
case SWAP_STATE_USING_1:
fnDebugMsg("using 1");
break;
case SWAP_STATE_USING_0:
fnDebugMsg("using 0");
break;
case SWAP_COMMAND_FAILURE:
fnDebugMsg("cmd error!");
break;
case SWAP_ERASE_FAILURE:
fnDebugMsg("erase error!");
break;
default:
fnDebugMsg("??");
break;
}
}Regards
Mark
Kinetis: http://www.utasker.com/kinetis.html
K22: http://www.utasker.com/kinetis/FRDM-K22F.html / http://www.utasker.com/kinetis/TWR-K22F120M.html
For the complete "out-of-the-box" Kinetis experience and faster time to market