This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

MSPM0G1518: Function DL_FlashCTL_executeClearStatus() not placed in RAM

Part Number: MSPM0G1518

Greetings,

recently when reviewing the implementation of our flash write/erase functionality for MSPM0, we found that DL API function DL_FlashCTL_executeClearStatus() performs the clear status command via flashctl->GEN.CMDEXEC but is not placed in device SRAM(like DL_FlashCTL_executeCommandFromRAM()), and this excerpt from the MSPM0 reference manual(6.3.1 Overview of Flash Controller Commands) suggests that setting CMDEXEC and waiting for its result is not supposed to be executed from the flash bank being operated on:

"The software sequence of setting the CMDEXEC bit and waiting for the CMDDONE response must be executed from either the device SRAM or from a different flash bank from the bank that is being operated on, as the flash controller will take control of the flash bank undergoing the operation. Reads to the flash bank that is being operated on while the flash controller is executing the command are not predictable."

We would like to ask whether using DL_FlashCTL_executeClearStatus() to clear flash status is correct if the function code is located in the same flash bank on which operation is performed.

P.S. Also we had a look at the flash write examples provided with MSPM0 SDK(flashctl_program_with_ecc to be exact), and those just use  DL_FlashCTL_executeClearStatus() and seem to write to the same bank where program code is stored. Latest SDK was used(v2.11.00.07)

 

Best regards,

Pavlo

  • Hi Pavlo,

    Yes, using DL_FlashCTL_executeClearStatus() while the function is located in the same flash bank is valid.

    The SRAM execution requirement applies to commands that actively program, erase, or otherwise operate on a flash bank. During those operations, reads from the affected bank are not reliable, so the command sequence must run from SRAM or from the other flash bank.

    DL_FlashCTL_executeClearStatus() is different. It only clears the FlashCTL command status and restores the protection state; it does not program or erase the flash array and does not take the bank out of read mode. For this reason, the function does not need to be placed in SRAM, and the usage shown in the SDK flashctl_program_with_ecc example is correct.

    The actual program or erase operation must still use the RAM-based DriverLib API, or execute from the alternate flash bank. Also ensure no interrupts or code fetches occur from the bank being modified during that operation. Hope this helps!

    -Brian

  • Thank you for the response Brian, it helps. 

    Using the occasion we would also like to get a clarification regarding interrupt disabling during operating on flash.

    Our current write/erase routine looks as follows:

    DL_FlashCTL_executeClearStatus(FLASHCTL);   // Legal to execute from flash
    DL_FlashCTL_unprotectSector(FLASHCTL, address, DL_FLASHCTL_REGION_SELECT_MAIN);  // Allow modification
    IRQ_DisableAll();  // globally disable interrupts to not fetch instructions from flash if interrupt happens during modification
    // Program / erase memory here from RAM
    IRQ_EnableAll();
    We already have a locking mechanism in place to serialize flash operations so that multiple writers don't race on flash controller access. Given that, could any issue potentially occur if DL_FlashCTL_executeClearStatus() or DL_FlashCTL_unprotectSector() get interrupted or delayed by a sudden interrupt load?
    Thanks in advance.
  • Hi Pavlo,

    An interrupt occurring during DL_FlashCTL_executeClearStatus() or DL_FlashCTL_unprotectSector() should not cause a functional issue, provided the interrupt handler does not access FlashCTL or start another flash operation. DL_FlashCTL_executeClearStatus() does not make the flash bank unavailable, so an interrupt only delays completion of the function. DL_FlashCTL_unprotectSector() updates the command write-protection register but does not start a program or erase command; execution from flash remains valid. The required order is still clear status first, then unprotect, because CLEAR_STATUS reapplies maximum protection.

    For the actual program or erase command:

    • Execute the command and completion wait from SRAM or the unaffected flash bank.
    • Disable maskable interrupts if their vectors, handlers, constants, or called functions could be fetched from the bank being modified.
    • Ensure the locking mechanism also prevents interrupt-context code from accessing FlashCTL.
    • Minimize the interval between unprotecting the sector and starting the command.

    For maximum robustness, disable interrupts before unprotecting the sector and restore the previous interrupt state afterward rather than unconditionally enabling all interrupts:

    uint32_t primask = __get_PRIMASK();
    
    __disable_irq();
    
    DL_FlashCTL_executeClearStatus(FLASHCTL);
    DL_FlashCTL_unprotectSector(
        FLASHCTL, address, DL_FLASHCTL_REGION_SELECT_MAIN);
    
    /* Program or erase using the RAM-based DriverLib API. */
    
    if (primask == 0U) {
        __enable_irq();
    }

    Therefore, the current sequence is functionally safe with the stated locking, but moving the interrupt-disable point before DL_FlashCTL_unprotectSector() reduces the unprotected window and makes the overall operation more atomic. Hope this helps!

    -Brian

  • Thank you for the information Brian.


    The behavior that originally prompted us to question our flash driver implementation was that occasionally, when context switch happened during DL_FlashCTL_unprotectSector(), the execution speed of the preempting RTOS task slowed down dramatically, in fact so much that it didn't allow any other task to run. We later established that it was due to the context switch happening in the window where DL_FlashCTL_unprotectSector() calls DL_FactoryRegion_getNumBanks() or DL_FactoryRegion_getMAINFlashSize() that disable ICACHE in CPUSS->CTL to access FACTORYREGION. So the fix was to just disable interrupts a bit earlier:

    DL_FlashCTL_executeClearStatus(FLASHCTL);   // Legal to execute from flash
    IRQ_DisableAll();  // do not fetch instructions and avoid context switch when instruction cache is disabled
    DL_FlashCTL_unprotectSector(FLASHCTL, address, DL_FLASHCTL_REGION_SELECT_MAIN);  // Allow modification
    // Program / erase memory here from RAM
    IRQ_EnableAll();
    Communicating the finding just in case you find it useful.
    BR,
    Pavlo