cancel
Showing results for 
Search instead for 
Did you mean: 

Bug: Option bytes driver can leave option bytes in inconsistent state

jblai.1
Associate II

Processor discovered on: STM32F103C8

Function with bug: HAL_FLASHEx_OBProgram

Parameter pOBInit pointing to a FLASH_OBProgramInitTypeDef object with the following values (which disables write protect on all flash pages) with pre-existing condition that write protect is already disabled on all pages:

OptionType having OPTIONBYTE_WRP bit set

WRPState set to OB_WRPSTATE_DISABLE

WRPPage set to 0xffffffff

The function FLASH_OB_DisableWRP gets called. This erases all the option bytes which sets them all to 0xff. Then for each of the 4 write protect bytes in the option bytes it checks the current value of the write protect status, and if it is already 0xff does not write that write protect byte...

   if(WRP0_Data != 0xFFU)

   {

    OB->WRP0 |= WRP0_Data;

     

    /* Wait for last operation to be completed */

    status = FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE);

   }

This code does not work with the above conditions because for each option bytes byte value its XOR'ed value is also stored in the option bytes flash. The XOR'ed value the programmer does not do the write into flash, the hardware does it automatically when an option byte is written. However, the flash erase has set them all to 0xff, including the XOR'ed values. A write of the 0xff value is required even if the value stored is already 0xff because that write sets the XOR'ed value. Without it the option bytes end up in an inconsistent state and the device cannot be reflashed without going into ST-LINK utility and clearing down all the option bytes. The solution is to remove the check on each existing value and write in anyway even if it's already 0xff like this...

   // if(WRP0_Data != 0xFFU) // this check on each of the 4 writes needs removing

   {

    OB->WRP0 |= WRP0_Data;

     

    /* Wait for last operation to be completed */

    status = FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE);

   }

This might sound like an unlikely scenario but it occurs when using the 2 user data bytes. To write these to a new value they need erasing first. It's only possible to erase all the option bytes so it's necessary to read all the existing option bytes, erase them, set the user data values and write the whole lot back. If write protect is off (as is the default) then using the user data option bytes results in this scenario.

0 REPLIES 0