STM32L0 Readout Protection and OBL_LAUNCH - Page 1
Forum section: electronics / general

author: voltsandjolts
author_rank: Unknown
timestamp: December 20, 2022, 11:27:05 am
content: I have the following code for an STM32L051 which programs the option bytes to change RDP level from 0 to 1.The change is implemented at the next power-on reset, when FLASH->OPTR is loaded from the option bytes.Code:/* Increase readout protection level from 0 to 1 */void RDP_level0_to_level1(void) {uint32_t primask_bit;primask_bit = __get_PRIMASK();__disable_irq();FLASH->PEKEYR = FLASH_PEKEY1; /* Unlock eeprom data memory and FLASH->PECR register access */FLASH->PEKEYR = FLASH_PEKEY2;FLASH->OPTKEYR = FLASH_OPTKEY1; /* Unlock option bytes */FLASH->OPTKEYR = FLASH_OPTKEY2;__set_PRIMASK(primask_bit);CLEAR_BIT(FLASH->PECR, FLASH_PECR_ERASE);/* PELOCK = 0, OPTLOCK = 0, ERASE = 0 as per RM section 3.3.4 Writing/erasing the NVM > Write Option bytes *//* 16-bit data is extended with its complemented value *//* WPRMOD=0 */OB->RDP = (~((uint32_t)OB_RDP_LEVEL_1) << 16) | (uint32_t)OB_RDP_LEVEL_1;while ((FLASH->SR & FLASH_SR_BSY) != 0)(void)0;SET_BIT(FLASH->PECR, FLASH_PECR_OPTLOCK);SET_BIT(FLASH->PECR, FLASH_PECR_PELOCK);/* FLASH->OPTR will have the updated value (from OB->RDP) after next power on reset */}That works but rather than wait for a power on reset, I would like to force a reload of the option bytes immediately use the OBL_LAUNCH bit:Code:SET_BIT(FLASH->PECR, FLASH_PECR_OBL_LAUNCH); /* Reboot and Force Option Bytes Load, OPTLOCK must be 0 */But adding that in causes the the device to hang:Code:void RDP_level0_to_level1_REBOOT(void) {__disable_irq();FLASH->PEKEYR = FLASH_PEKEY1; /* Unlock eeprom data memory and FLASH->PECR register access */FLASH->PEKEYR = FLASH_PEKEY2;FLASH->OPTKEYR = FLASH_OPTKEY1; /* Unlock option bytes */FLASH->OPTKEYR = FLASH_OPTKEY2;CLEAR_BIT(FLASH->PECR, FLASH_PECR_ERASE);/* PELOCK = 0, OPTLOCK = 0, ERASE = 0 as per RM section 3.3.4 Writing/erasing the NVM > Write Option bytes *//* 16-bit data is extended with its complemented value *//* WPRMOD=0 */OB->RDP = (~((uint32_t)OB_RDP_LEVEL_1) << 16) | (uint32_t)OB_RDP_LEVEL_1;while ((FLASH->SR & FLASH_SR_BSY) != 0)(void)0;SET_BIT(FLASH->PECR, FLASH_PECR_OBL_LAUNCH); /* Reboot and Force Option Bytes Load, OPTLOCK must be 0 *//* shouldn't get here */}I've tried various things, including running that function in RAM but am kinda stuck. The RM is somewhat lacking on OBL_LAUNCH information other than 'set this bit to load and reboot'.The RESET pin just has 100nF to GND so device should be able to drive RESET without problem.Has anyone successfully used OBL_LAUNCH ?

author: wek
author_rank: Frequent Contributor
timestamp: December 20, 2022, 11:49:53 am
content: > But adding that in causes the the device to hang:Define "hang".JW

author: voltsandjolts
author_rank: Unknown
timestamp: December 20, 2022, 11:58:29 am
content: By 'hang', I mean the function doesn't return (as expected) but the device doesn't reboot either.The function does return if the line that sets OBL_LAUNCH is removed, so it is 'hanging' at that point.After a power on reset, the RDP is at level 1, so the option byte programming (prior to OBL_LAUNCH) still worked.

author: voltsandjolts
author_rank: Unknown
timestamp: December 20, 2022, 12:11:21 pm
content: Hmm, this sounds like my issue...https://community.st.com/s/question/0D53W00001B0wNxSAJ/stm32g0b1-programming-option-bytes-stopped-after-obllaunch

author: voltsandjolts
author_rank: Unknown
timestamp: December 20, 2022, 12:17:09 pm
content: OK, the thread above links to this solution:https://community.st.com/s/question/0D50X0000AwWZjDSQW/problem-with-reloading-option-bytes-stm32l452reQuoteI will give that a try....

author: wek
author_rank: Frequent Contributor
timestamp: December 20, 2022, 12:44:31 pm
content: I don't have first-hand experience, but I also consider outright hardware bugs to be quite rare.> device doesn't reboot eitherIt may have performed the system reset but causing a surprise by not running your code, or not in a way you expected. For examle, it may have entered the bootloader for any reason, or you may have debug active before setting OBL_LAUNCHQuote from: RM0377Anyway, exit from Standby should work, it's documented too inOption byteschapter of RM0377.JW

author: voltsandjolts
author_rank: Unknown
timestamp: December 20, 2022, 12:49:00 pm
content: That could indeed be the issue, but the first fix they give is apply a POR which I want to avoid!The standby mode solution is working for me, no POR required so I'll go with that.Thanks for your time.Edit:Another option given in the above linked threads was to setup a watchdog to reset the mcu, then set the OBL_LAUNCH bit.The idea being the watchdog resets the mcu and clears the 'hung' state caused by OBL_LAUNCH.Tried it using IWDG, but didn't work for me, mcu remained in 'hung' state, no reset occurred.

author: wek
author_rank: Frequent Contributor
timestamp: December 20, 2022, 05:40:05 pm
content: Quote from: voltsandjolts on December 20, 2022, 12:49:00 pmWatchdog reset is "just" a system reset, you might've as well done a software reset. Neither of them is supposed to reload the Option bytes; contrary to explicit OBL_LAUNCH and the Standby wakeup, and of course the power-up reset.I wonder what exactly the differences are, but we'd need an ST insider to get a conclusive answer to this.JW

author: voltsandjolts
author_rank: Unknown
timestamp: December 21, 2022, 06:45:38 pm
content: Quote from: wek on December 20, 2022, 05:40:05 pmI couldn't do a software reset because the mcu hangs after setting OBL_LAUNCH.Hence using the IWDG (setup beforehand) to do the reset, in the hope that setting OBL_LAUNCH would cause option byte reload.That didn't work.I ended up using the IWDG to exit standby mode so early in main() I have something this:Code:if ((FLASH->OPTR & FLASH_OPTR_RDPROT) == (uint32_t)OB_RDP_LEVEL_0) {RDP_level0_to_level1(); /* enable readout protection level 1 *//* To load new options into FLASH->OPTR from OB->RDP we need to wake from standby mode.* Execution after exit from standby mode is same as a reset.* For simplicity, use the IWDG to exit from standby.*/IWDG->KR = 0xCCCC;/* start */IWDG->KR = 0x5555;/* enable access to PR and RLR regs */IWDG->PR = IWDG_PR_PR_2; /* /64 prescaler for the dedicated 32kHz LSI clock = 512Hz */IWDG->RLR = 256;/* count down from this value (256 is about 0.5secs at 512Hz) */while (IWDG->SR)/* wait for setup to complete (slow clock domain) */(void)0;IWDG->KR = 0xAAAA;/* refresh (feed) the watchdog */__disable_irq();enter_standby_mode();/* never get here, standby exit is same as reset */}