cancel
Showing results for 
Search instead for 
Did you mean: 

Option Byte Programming

Carl_G
Senior III

I want to check and ensure the option bytes are correct from with my executing program. But writing the option bytes is very flaky if the IWDG is active. For some reason, there is a stall at "FLASH_CR_OBL_LAUNCH". Or maybe it makes it past but not soon after the watch dog resets the MCU and the option bytes are not written. This is an ongoing cycle forever.

If I disable the IWDG then things work normally. Any idea why?

 

void CodeProtect()
{
    bool needsUpdate = false;

    // Unlock FLASH
    if (READ_BIT(FLASH->CR, FLASH_CR_LOCK) != 0x00U)
    {
      /* Authorize the FLASH Registers access */
      WRITE_REG(FLASH->KEYR, FLASH_KEY1);
      WRITE_REG(FLASH->KEYR, FLASH_KEY2);
    }

    // Unlock Option Bytes
    if (READ_BIT(FLASH->CR, FLASH_CR_OPTLOCK) != 0x00U)
    {
      /* Authorizes the Option Byte register programming */
      WRITE_REG(FLASH->OPTKEYR, FLASH_OPTKEY1);
      WRITE_REG(FLASH->OPTKEYR, FLASH_OPTKEY2);
    }

    // --- Check and update RDP level ---
    uint32_t optr = FLASH->OPTR;
    const uint32_t currentRDP = (optr & FLASH_OPTR_RDP_Msk) >> FLASH_OPTR_RDP_Pos;

    if (currentRDP != OB_RDP_LEVEL_1) {
        optr = (optr & ~FLASH_OPTR_RDP_Msk) | (OB_RDP_LEVEL_1 << FLASH_OPTR_RDP_Pos);
        FLASH->OPTR = optr;
        needsUpdate = true;
    }

    // --- Check and update WRP area ---
    const uint32_t wrp1ar = FLASH->WRP1AR;
    const uint32_t currentStart = wrp1ar & FLASH_WRP1AR_WRP1A_STRT_Msk;
    const uint32_t currentEnd   = (wrp1ar & FLASH_WRP1AR_WRP1A_END_Msk) >> FLASH_WRP1AR_WRP1A_END_Pos;

    if ((currentStart != kWRPStart) || (currentEnd != kWRPEnd)) {
        FLASH->WRP1AR = ((kWRPEnd << FLASH_WRP1AR_WRP1A_END_Pos) & FLASH_WRP1AR_WRP1A_END_Msk)
                      | (kWRPStart & FLASH_WRP1AR_WRP1A_STRT_Msk);
        needsUpdate = true;
    }

    // --- Program option bytes if needed ---
    if (needsUpdate) {
        UpdateOptionBytes();
    }

    /* Set the OPTLOCK Bit to lock the FLASH Option Byte Registers access */
    SET_BIT(FLASH->CR, FLASH_CR_OPTLOCK);
    /* Set the LOCK Bit to lock the FLASH Registers access */
    SET_BIT(FLASH->CR, FLASH_CR_LOCK);

    if (needsUpdate) {
        /* Set the bit to force the option byte reloading */
        SET_BIT(FLASH->CR, FLASH_CR_OBL_LAUNCH);
        //__NOP();
        while (true);  // Will reset
    }
}
__RAM_FUNC
__NOINLINE
static void UpdateOptionBytes()
{
    /**
     * Note: This must be in RAM. When you execute OPTSTRT it will begin a FLASH write. This will block the CPU if it
     * interacts with FLASH. This will prevent servicing the WDOG. If you run the code from RAM it does not get blocked
     * and can service the WDOG.
     *
     * Note: When trying to clear the option bytes with the stm32programmer, first write RDP to BB. Then, at the same
     * time write RDP to AA and Write Protection to None. Then erase FLASH. Then do it again because after you wrote
     * the option bytes the program runs again and re-writes the Write Protection bytes but fortunately not the RDP.
     */

    __disable_irq();
    /* Set OPTSTRT Bit */
    SET_BIT(FLASH->CR, FLASH_CR_OPTSTRT);

    while (FLASH->SR & FLASH_SR_BSY1) {
        IWDG->KR = 0xAAAA;
        __NOP();
    }
    /* Clear SR register */
    FLASH->SR = FLASH_SR_CLEAR;
    while (FLASH->SR & FLASH_SR_CFGBSY) {
        IWDG->KR = 0xAAAA;
        __NOP();
    }
}

 

 

2 REPLIES 2
TDK
Super User

The reference manual says to do a POR rather than launching option bytes if you set RDP through software.

 

Erasing and writing to flash (where option bytes are stored) takes some time, probably in the tens of ms range. How is IWDG configured that it's resetting so quickly?

You could also try reloading it in the while (true) look after launching option bytes. Unsure if that'll do anything.

If you feel a post has answered your question, please click "Accept as Solution".
Carl_G
Senior III

Where is that in the manual? I didn't see it. Thats really my main problem. The OBL_Launch isn't really working.

My routine runs in RAM and the IWDG is serviced while waiting on flash to be free. This part works. But after issuing the OBL_Launch, it doesn't really launch and the iwdg causes a reset. Iwdg is set for 7.5ms.

I get really strange behavior when i try to debug this by port toggling. I don't see the ports for some reason. My guess is the OBL Launch puts the mcu in some mode but takes more than 7ms to complete. And this mode does not allow code execution so no iwdg servicing can happen even if running from  RAM.

I think I can try extending the iwdg timeout until i figure out how long it takes. If i set a port high just before the OBL Launch and low just after it what happens is the output rises but before it can even hit 3.3v it drops asymptotically to 0 in uS.