For reference, this is the code I started to write to test/initialize the new swap mechanism, which 'bricked' my 1.2 part (which means it set up the swap mechanism, which I then couldn't use for my purposes, and in that rev was irreversable).
I BELIEVE this sequence will set address 0x3F0 (and the mirror address at 0x403F0 in the other bank) for the swap system flags. I don't know if this is a particularly 'good' address to use, but note that whatever address you dedicate for this specifically protects the enclosing sector from erase activity except in the very specific sequence to run from one bank and erase the other in prep for this whole update-then-swap scenario.
if( (fnFlashNow(FCMD_SWAP_CONTROL, 0x3F0, 0x08FF) & FTFL_FSTAT_MGSTAT0_MASK) == 0 )
//Command 8 == report swap status
{
if(FTFL_FCCOB5 == 0 )
fnFlashNow(FCMD_SWAP_CONTROL, 0x3F0, 0x01FF); //'virgin', initialize swap system
//Command 1 == set swap indicator address
else if(FTFL_FCCOB5 == 1 ) //'Normal' ready state -- swap process NOT started
{ //FTFL_FCCOB6 indicates which block is at address 0
}else //If we had a reset while the swap state machine was not 'Ready', we can't count on the new image
{
}
}else //Nonzero MGSTAT0 bit indicates some kind of fault during a swap-command execution
{
}
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 = (uint8_t)(ulWord >> 8);
FTFL_FCCOB5 = (uint8_t)(ulWord);
case FCMD_ERASE_FLASH_SECTOR:
FTFL_FCCOB1 = (uint8_t)(ptrWord >> 16);
FTFL_FCCOB2 = (uint8_t)(ptrWord >> 8);
FTFL_FCCOB3 = (uint8_t)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
}