SDK 2.0 FLASH_Erase causing core lockup

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

SDK 2.0 FLASH_Erase causing core lockup

Jump to solution
1,730 Views
cwpaynter
Contributor III

I am using KSKD 3.0, with SDK 2.0 to run a FREERtos project on a standalone board with a MK22FN256VLL12 on it.

During the initialization, before the RTOS is started with vTaskStartScheduler(), I am able to erase and write to the last couple of sectors of Flash with the following code:

 

uint32_t try_flash_erase_in_rtos( void )

{

    uint32_t destAdrss = SETTINGS_0_START;

    status_t        result;

 

    if (!nv_initialized) {

        NVInit();

        nv_initialized = 1;

    }

 

    // try disabling interrupts

    // taskENTER_CRITICAL();

    // taskDISABLE_INTERRUPTS();

    __disable_irq();

    // erase sector before trying to write (can only write 0 bits, not 1)

    result = FLASH_Erase(&flashDriver, destAdrss, FSL_FEATURE_FLASH_PFLASH_BLOCK_SECTOR_SIZE, kFLASH_apiEraseKey);

    if (kStatus_FLASH_Success != result)

    {

        return FALSE;

    }

    // taskENABLE_INTERRUPTS();

    // portENABLE_INTERRUPTS();

    // taskEXIT_CRITICAL();

    __enable_irq();

 

    __disable_irq();

    flash_security_state_t securityStatus;

    result = FLASH_GetSecurityState(&flashDriver, &securityStatus);

    // now write the struct to the flash

    result = FLASH_Program(&flashDriver, destAdrss, (uint32_t *)&SystemSettings, sizeof(SystemSettings));

    uint32_t failAddr, failDat;

    result = FLASH_VerifyProgram(&flashDriver, destAdrss, sizeof(SystemSettings), (uint32_t *)&SystemSettings, kFLASH_marginValueUser, &failAddr, &failDat);

    __enable_irq();

    if (kStatus_FLASH_Success != result) {

        return FALSE;

    }

    return TRUE;

}

 

However, if I try to execute that code from inside a running task, The call to FLASH_Erase() causes a core lockup and restarts my program.  If I manually erase the whole chip first, and comment out the call to FLASH_Erase(), the call to FLASH_Write() works fine with no reset, and actually does program the flash.

 

From tracing through the SDK code, it appears that the flash-erasing code is copied to RAM, so I don't think it's an issue of writing to flash while running code from it.  I'm also disabling interrupts, so I don't think I'm getting any unwanted execution of ISR code from Flash.  I did see a reference to resetting the flash cache, but there is at least some mention of the cache in the call to the RAM function, so I'm assuming it's addressed...

 

much thanks for any suggestions.   Chris

 

BTW, the clock configuration is taken directly from the SDK flash demo code; core clock is 80 MHz, flash clock is 20 MHz, running in PEE mode.

Labels (1)
1 Solution
1,103 Views
cwpaynter
Contributor III

OK, everything's working well now.  Working code is pasted below.

Originally I started with the flash_erase_program_verify sample code for the FRDMK22F dev board, and it's pretty straightforward.  Problems come up when:

  1. I moved to the smaller MK22FN256VLL12 processor, which has only one block of flash.  The dev board has two, so the demo code runs from block 0, and the sectors which are read and written are in block 1, so you don't get Read-While-Write errors.
  2. I employed the sample code in a FREERtos task, where interrupts are flying, including a bunch of my own.  Again, the larger chip on the dev board would have been fine, 'cause the ISRS would have been in block 0, and writes to block 1.
  3. For some reason, if I don't disable interrupts during the flash verify operations, I still get the core lockup.  I would have thought that was a read-only operation for flash, so no conflict, but there you go.
  4. None of the interrupt disable mechanisms I tried prevented the core lockup until I found a reference to the low level __disable_irq() calls.  Calling taskENTER_CRITICAL(),  taskDISABLE_INTERRUPTS(), portDISABLE_INTERRUPTS(), none of those prevented the core lockup. 

   // erase sector before trying to write (can only write 0 bits, not 1).  Note that ALL interrupts

    // are disabled, because FLASH_Erase() needs to copy some code into RAM and run there with

    // no read access to Flash (i.e ISRs) wile the erase operation is going on.

    __disable_irq();

    result = FLASH_Erase(&flashDriver, destAdrss, FSL_FEATURE_FLASH_PFLASH_BLOCK_SECTOR_SIZE, kFLASH_apiEraseKey);

    __enable_irq();

    if (kStatus_FLASH_Success != result)

    {

        return ERASE_FAILED;

    }

    // make sure we actually managed to erase the sector

    __disable_irq();

    result = FLASH_VerifyErase(&flashDriver, destAdrss, FSL_FEATURE_FLASH_PFLASH_BLOCK_SECTOR_SIZE, kFLASH_marginValueUser);

    __enable_irq();

    if (kStatus_FLASH_Success != result) {

        return ERASE_FAILED;

    }

    // now write the struct to the flash - interrupts disabled again to prevent any read access to flash while writing.

    // Note that the write size needs to be a multiple of 8 bytes.

    __disable_irq();

    result = FLASH_Program(&flashDriver, destAdrss, (uint32_t *)&SystemSettings, sizeof(SystemSettings));

    __enable_irq();

    if (kStatus_FLASH_Success != result) {

        return WRITE_FAILED;

    }

    // verify the write

    __disable_irq();

    result = FLASH_VerifyProgram(&flashDriver, destAdrss, sizeof(SystemSettings), (uint32_t *)&SystemSettings, kFLASH_marginValueUser, &failAddr, &failDat);

    __enable_irq();

    if (kStatus_FLASH_Success != result) {

        return WRITE_FAILED;

    }

View solution in original post

3 Replies
1,103 Views
xiangjun_rong
NXP TechSupport
NXP TechSupport

Hi, Chris,

Regarding your question, I have checked the flash erase code, it uses the polling mode to check if the erasing operation is over or not.

status_t FLASH_Erase(flash_config_t *config, uint32_t start, uint32_t lengthInBytes, uint32_t key)

{

.....

flash_command_sequence(config);

....

}

flash_command_sequence(flash_config_t *config)

{

....

while (!(FTFx->FSTAT & FTFx_FSTAT_CCIF_MASK))

{}

....

}

I suppose that the RTOS scheduler will stick to the while() loop, can not schedule the other task. I suggest you add the task delay function so that the FLASH_Erase() function can give up the control and block itself. you can change the code as following.

flash_command_sequence(flash_config_t *config)

{

while (!(FTFx->FSTAT & FTFx_FSTAT_CCIF_MASK))

{

vTaskDelay(1000us);

}

}

This is my guess, pls have a try.

BR

XiangJun Rong

0 Kudos
1,103 Views
cwpaynter
Contributor III

Thanks for your answer XiangJun ,

At the moment, my code is actually working, and I'm experimenting to understand why - the code that I posted was not working when I posted it, but now seems to work for some reason.  I assume that I missed something which I later fixed while experimenting.  I have found that disabling interrupts with __disable_irq(); is the only way to make it work, none of the other methods do (taskENTER_CRITICAL(),  taskDISABLE_INTERRUPTS(), portDISABLE_INTERRUPTS()). 

Regarding your suggestion, I have disabled interrupts, so if I understand correctly, the RTOS scheduler cannot run until the Flash operation is complete, which is fine - it seems to take about 7.6 ms to do the sector erase, during which time interrupts are disabled.  In my application I can tolerate that, as the flash writes will only happen during initial setup of the product and not while running in the field. 

Your suggested change would apply in my case to a piece of code which is #ifdef'ed out by the macro FLASH_DRIVER_IS_FLASH_RESIDENT being #defined.  The same while loop also appears in the RAM copy of that function, flash_run_command() - in that case, would not calling vTaskDelay() execute code from Flash, which is the thing I'm trying avoid? 

Thanks again for spending time thinking about this.  When I'm more confident in what's making it work, I'll post a more complete answer.

Chris

0 Kudos
1,104 Views
cwpaynter
Contributor III

OK, everything's working well now.  Working code is pasted below.

Originally I started with the flash_erase_program_verify sample code for the FRDMK22F dev board, and it's pretty straightforward.  Problems come up when:

  1. I moved to the smaller MK22FN256VLL12 processor, which has only one block of flash.  The dev board has two, so the demo code runs from block 0, and the sectors which are read and written are in block 1, so you don't get Read-While-Write errors.
  2. I employed the sample code in a FREERtos task, where interrupts are flying, including a bunch of my own.  Again, the larger chip on the dev board would have been fine, 'cause the ISRS would have been in block 0, and writes to block 1.
  3. For some reason, if I don't disable interrupts during the flash verify operations, I still get the core lockup.  I would have thought that was a read-only operation for flash, so no conflict, but there you go.
  4. None of the interrupt disable mechanisms I tried prevented the core lockup until I found a reference to the low level __disable_irq() calls.  Calling taskENTER_CRITICAL(),  taskDISABLE_INTERRUPTS(), portDISABLE_INTERRUPTS(), none of those prevented the core lockup. 

   // erase sector before trying to write (can only write 0 bits, not 1).  Note that ALL interrupts

    // are disabled, because FLASH_Erase() needs to copy some code into RAM and run there with

    // no read access to Flash (i.e ISRs) wile the erase operation is going on.

    __disable_irq();

    result = FLASH_Erase(&flashDriver, destAdrss, FSL_FEATURE_FLASH_PFLASH_BLOCK_SECTOR_SIZE, kFLASH_apiEraseKey);

    __enable_irq();

    if (kStatus_FLASH_Success != result)

    {

        return ERASE_FAILED;

    }

    // make sure we actually managed to erase the sector

    __disable_irq();

    result = FLASH_VerifyErase(&flashDriver, destAdrss, FSL_FEATURE_FLASH_PFLASH_BLOCK_SECTOR_SIZE, kFLASH_marginValueUser);

    __enable_irq();

    if (kStatus_FLASH_Success != result) {

        return ERASE_FAILED;

    }

    // now write the struct to the flash - interrupts disabled again to prevent any read access to flash while writing.

    // Note that the write size needs to be a multiple of 8 bytes.

    __disable_irq();

    result = FLASH_Program(&flashDriver, destAdrss, (uint32_t *)&SystemSettings, sizeof(SystemSettings));

    __enable_irq();

    if (kStatus_FLASH_Success != result) {

        return WRITE_FAILED;

    }

    // verify the write

    __disable_irq();

    result = FLASH_VerifyProgram(&flashDriver, destAdrss, sizeof(SystemSettings), (uint32_t *)&SystemSettings, kFLASH_marginValueUser, &failAddr, &failDat);

    __enable_irq();

    if (kStatus_FLASH_Success != result) {

        return WRITE_FAILED;

    }