cancel
Showing results for 
Search instead for 
Did you mean: 

STM32WLE5CC MCU brick when trying to set Brownout Reset level

IFant.1
Associate II

Greetings

I have been trying to set the BOR option byte via software in a STM32WLE5CC (as part of a RAK3172 evaluation board), but even following various guides i have not been successful in this endeavor, often resulting in the MCU being bricked and requiring intervention via CubeProgrammer to reset the corrupted option bytes followed by reflashing of the firware via CubeIDE.

The code is as follows:

int main(void)
{
	/* USER CODE BEGIN 1 */
 
	/* USER CODE END 1 */
 
	/* MCU Configuration--------------------------------------------------------*/
 
	/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
	HAL_Init();
 
	/* USER CODE BEGIN Init */
 
	/* USER CODE END Init */
 
	/* Configure the system clock */
	SystemClock_Config();
 
	/* USER CODE BEGIN SysInit */
	MX_GPIO_Init();
 
	/* USER CODE END SysInit */
 
	/* Initialize all configured peripherals */
        SystemApp_Init();
	/* USER CODE BEGIN 2 */
 
 
 
	HAL_StatusTypeDef status;
	FLASH_OBProgramInitTypeDef FLASH_Handle;
 
	if ( (FLASH->OPTR & FLASH_OPTR_BOR_LEV_Msk) != OB_BOR_LEVEL_4){
 
		HAL_FLASHEx_OBGetConfig(&FLASH_Handle);
 
		FLASH_Handle.OptionType = OPTIONBYTE_USER;
		FLASH_Handle.UserConfig = FLASH_Handle.UserConfig | (uint32_t)OB_BOR_LEVEL_4;
		FLASH_Handle.UserType = OB_USER_BOR_LEV;
		status= HAL_FLASH_Unlock();
		status= HAL_FLASH_OB_Unlock();
 
		status=HAL_FLASHEx_OBProgram(&FLASH_Handle);
		if (status != HAL_OK)
		{
 
			APP_LOG(TS_OFF, VLEVEL_M, "Error during programming %x\r\n", (uint32_t)status);
			return;
		}
 
 
		HAL_FLASH_OB_Lock();
					HAL_FLASH_Lock();
 
 
		status=HAL_FLASH_OB_Launch();
		if(status==HAL_ERROR){
			APP_LOG(TS_OFF, VLEVEL_M, "Error during launch\r\n");
		}
 
 
	}
 
 
 
 
	APP_LOG(TS_OFF, VLEVEL_M, "FLASH->OPTR is = %X\r\n", (uint32_t)READ_REG(FLASH->OPTR));
 
	/* USER CODE END 2 */
 
	/* Infinite loop */
	/* USER CODE BEGIN WHILE */
	while (1)
	{
 
		//APP_LOG(TS_OFF, VLEVEL_M, "Loop\r\n");
 
		/* USER CODE BEGIN 3 */
	}
	/* USER CODE END 3 */
}

In this configuration, HAL_FLASH_OB_Launch returns HAL_ERROR rather than causing a reset of the MCU to load the new option bytes, thus resulting in the option bytes not being effectively written to the register, successive power cycling (with or without a debugger attached) show that the option bits were not overwrote

When removing both unlock functions, the MCU hangs/bricks with power cycling failing to resolve the issue, the RDP field is corrupted to FF and some other parts of the flash seems corrupted as well thus preventing reflashing via CubeIDE

Only intervention through CubeProgrammer to reset the option bytes followed by reflashing via CubeIDE has shown any effectiveness at recovering from said state.

Any suggestion in how to fix this issue? Thanks in advance.

Edit: just in case they might be needed, i attach images of the Option Bytes read from the ST-LINK

Edit #2: i have noticed that during the various write operations (es: in FLASH_OB_OptrConfig), the register value does not appear to be updated, whether this is a limitation of the debugger or of the printout via APP_LOG erroneously returning a old value i do not know

14 REPLIES 14
TDK
Guru

See example for how to write option bytes in a program here:

https://github.com/STMicroelectronics/STM32CubeWL/blob/747d4e27df07dcfc995b54f8af8a0bee38dfef8d/Projects/NUCLEO-WL55JC/Examples/FLASH/FLASH_WriteProtection/Src/main.c

Note that HAL_FLASH_OB_Launch needs to be called before locking the option bytes, and that it resets the chip.

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

Thank you but even after looking at the linked code i cannot readily understand what it is doing differently in order to work.

As i said before, removing the locking functions (or moving them after the launch function for that matter) bricks the MCU

In my code i perform the following

-set OptionType to OPTIONBYTE_USER

-set UserConfig to the one obtained via GetConfig bitwise OR-ed with OB_BOR_LEVEL_4

-set UserType to OB_USER_BOR_LEV

(this all following examples of other users trying to change BOR levels)

-unlock flash

-unlock option bytes

-program the optionbytes

(here the flash is re-locked but as i said, not doing that bricks the MCU in the following step)

-call the Launch function <-brick happens here

in the code linked however it seems to follow the same process (barring the write protection enable/disable within compiler guards and the fact it's not changing BOR level)

TDK
Guru

Perhaps explain what you mean by "bricked". Clearly if STM32CubeProgrammer still connects, the chip is responsive. Perhaps your program just doesn't do what you think it does.

When you reconnect with STM32CubeProgrammer (and not locking before launching), what are the option byte values?

I didn't dig into it, but verify that "FLASH_Handle.UserConfig = FLASH_Handle.UserConfig | (uint32_t)OB_BOR_LEVEL_4;" provides a valid level. Changing values within a bit field sometimes requires resetting bits, and OR-ing only sets common bits.

If you feel a post has answered your question, please click "Accept as Solution".
Bruno_ST
ST Employee

Hello @IFant.1​ 

I think i understood the issue you have faced !

First of all, it is very IMPORTANT to not power-off the board to interrupt the OB Launch otherwise, the content of the Option bytes can switch into un-predictable state. If you get 0xFF for RDP, it probably means that the process to change the option bytes have been interrupted while the flash page was being erased... Did you do that ?

Second, the code FLASH_Handle.UserConfig = FLASH_Handle.UserConfig | (uint32_t)OB_BOR_LEVEL_4; is wrong.

It should only be :

FLASH_Handle.UserConfig = OB_BOR_LEVEL_4;

Because imagine you have BOR level 1 (valid also if BOR is level 2 or 3)

FLASH_Handle.UserConfig = FLASH->OPTR = 0x3ffff2aa

Then calling you code with change to BOR level 4, change to :

function FLASH_OB_OptrConfig()

 optr = FLASH->OPTR; => optr = 0x3ffff2aa

 optr &= ~(UserType | FLASH_OPTR_RDP); => optr = 0x3ffff000

FLASH->OPTR = (optr | UserConfig | RDPLevel) => optr = 0x3ffffaaa

means bits 101 is NOT a known BOR value !

Most important when writing code that change the option bytes like this is to avoid to break the OBLaunch() process. (ex : add big delay to be not too repetitive, wait for button, key pressed, etc...)

BR,

Bruno

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.

True, "bricked" might not be the precise term.

The setup is as such (starting from a "bricked", for lack of a better word, board: through CubeProgrammer the option bit for BOR level is set to 4 and the RDP is set to AA, the program is then flashed to the board, successively the BOR level is set to a value different than 4 via CubeProgrammer

What happens is the following, when the code reaches HAL_FLASH_OB_Launch(); the board freezes and becomes unresponsive, i no longer receive messages via UART, pressing the hardware reset button (connected to the reset pin of the mcu) seems to be ineffective (or at least, it does not cause the program to send UART messages) and attempts to re-flash via CubeIDE fail with the following error

Error: Data mismatch found at address 0x08000001 (byte = 0x00 instead of 0x80)

Furthermore, through CubeProgrammer i can see that

1) the BOR level remains the same as before (ie, it was not changed to 4 by the software)

2) the readout protection assumes value 0xFF

3) at address 0x08000000 onward there are only 0s

When attempting to change the option bytes via CubeProgrammer, attempting to change the RDP from FF to AA fails unless either the BOR level (any value) is written first/alongside it or the RDP is first changed to BB and then AA

When looking at the option bits in a working configuration (ie: the BOR level is already set to 4 and so the code never reaches unlock or launch, they are as follows (as printed by UART and checked by CubeProgrammer)

Value printed to UART->3FFF08AA

RDP: AA

BOR_LEV: 4

ESE: 0

nRST_STOP/STDBY/SHDW: all 0

IWDG_SW/STOP/STDBY: all 1

WWDG_SW: 1

nBOOT1: 1

SRAM_PE/RST: both 1

nSWBOOT0: 1

nBOOT0: 1

BOOT_LOCK: 0

Hi @IFant.1​ 

HAL_FLASH_OB_Launch(); the board freezes and becomes unresponsive ==> It is expected. After a OB launch you get a have an hardware reset ! (due to prog of Options Bytes)

i no longer receive messages via UART, pressing the hardware reset button (connected to the reset pin of the mcu) seems to be ineffective ==> Again it think it is because you don't use a direct print blocking function like HAL_UART_Transmit(). Using APP_LOG() is not a good choice because it used DMA under Interrupt, so executing it return immediately to main code execution ! (uart trace doesn't have time to be outputted as you are already calling HAL_FLASH_OB_Launch()

RDP from FF to AA fails unless either the BOR level (any value) is written first/alongside it or the RDP is first changed to BB and then AA ==> You are lucky because you can brick your board forever without having the capability to recover from this situation !

BR,

Bruno

Ps: When finished please choose best answer to improve stcommunity results

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.

While it's possible i might have done so by pressing the hardware reset button, i only did so after several seconds of unresponsiveness from the board (a amount of time that, at least at a first guess, would exclude it being just the normal time the board takes to load the new option bits)

Furthermore, the corruption of RDP to 0xFF happens every time the code reaches HAL_FLASH_OB_Launch(); (of course, without first re-locking the Flash, that's a given)

for the UserConfig i changed it as you shown but it does not appear to make a difference, the MCU still stops working after reaching Launch(); , i have also tried to add a HAL_Delay(5000); right before the Launch(); it didn't work

You use a RAK3172 module correct ? Do you supply it with a steady 3.3V ? externally ?

Are you able to change BOR level to 4 with STM32CubeProgrammer ? But not with above program + the fix that i talked about in previous post ?

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.

Yes, the module is connected to the PC via USB, for both power supply and UART communication, and to a STLINK-V3SET debugger/programmer (for use with CubeProgrammer and CubeIDE)

With CubeProgrammer i am able to change the option bits (and in fact i've done so multiple times in order to recover from said issue and be able to flash the MCU again with CubeIDE), however i have not been able to change the option bits from software

Pasting the relevant modified code for reference (it's possible i might have missed/misunderstood something and i haven't noticed)

		HAL_FLASHEx_OBGetConfig(&FLASH_Handle); 
 
		FLASH_Handle.OptionType = OPTIONBYTE_USER;
		FLASH_Handle.UserConfig = (uint32_t)OB_BOR_LEVEL_4;
		FLASH_Handle.UserType = OB_USER_BOR_LEV;
		HAL_FLASH_Unlock();
		HAL_FLASH_OB_Unlock();
 
		status=HAL_FLASHEx_OBProgram(&FLASH_Handle);
		APP_LOG(TS_OFF, VLEVEL_M, "FLASH->OPTR after program is = %X\r\n", (uint32_t)READ_REG(FLASH->OPTR));
 
		if (status != HAL_OK)
		{
 
			APP_LOG(TS_OFF, VLEVEL_M, "Error during programming %x\r\n", (uint32_t)status);
			return;
		}
 
 
 
		HAL_Delay(5000);
 
		status=HAL_FLASH_OB_Launch();
		if(status==HAL_ERROR){
			APP_LOG(TS_OFF, VLEVEL_M, "Error during launch\r\n");
		}
 
		HAL_FLASH_OB_Lock();
		HAL_FLASH_Lock();