Report Swap status always causes reset

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Report Swap status always causes reset

Jump to solution
925 Views
rev
Contributor III

I can successfully erase and program Flash in either bank, however as soon as I perform a Swap Report Status Operation (CCOB4 = 0x08) my code resets. I can't find this behavior documented anywhere.  The device is MK221M0AVLL12. This is the first step in determining the Swap state, so I'm blocked from running any other Swap control commands until this is resolved.

The actual reset occurs when the CCIF bit is written to start the operation (in the "FLASH_FlashCommandSequenceStart()" function).

Any ideas why this operation might be causing a reset?

Labels (1)
0 Kudos
1 Solution
739 Views
mjbcswitzerland
Specialist V

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

View solution in original post

4 Replies
740 Views
mjbcswitzerland
Specialist V

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

739 Views
rev
Contributor III

Thanks Mark. When I compared your sequence to mine I realized I forgot to globally disable interrupts! Silly mistake, but things are stable now with "__disable_irq()" added to my code. Interesting that a simple Flash swap status operation is so intolerant of interrupts, while other erase/write operations are [mostly?] OK.

I appreciate the help.

0 Kudos
739 Views
mjbcswitzerland
Specialist V

Jonathan

If you are deleting/programming Flash in the alternative bank to the one that interrupt code will be using there is no need to disable interrupts and run code from RAM.

The swap routines themselves will of course require all such activity to be disabled since the complete Flash (both banks) is then busy.

Regards

Mark

0 Kudos
739 Views
rev
Contributor III

Mark,

Good point on leaving interrupts enabled for some Flash operations. I've now got two versions (with and without interrupts) for more flexibility in my code.

Also, your original feedback about the importance of CCOB[4..7] having 0xFF is absolutely correct.  Although it doesn't cause resets, I just found that certain Flash swap operations give an Access-error if unused CCOB registers in that range are not 0xFF. The RM docs could be clearer is this regard.

-- Jon

0 Kudos