Skip to main content
rengl
Associate II
February 27, 2026
Question

Option Bytes programing (NBOOT_SEL & WRP) problem

  • February 27, 2026
  • 0 replies
  • 141 views

Hi,

programing NBOOT_SEL and WRP in the firmware leads to strange behavior of the MCU. After running the code below and reseting the MCU, I can still debug with CubeIDE to some extent by connecting without downloading the firmware, but I can only see that the MCU is stuck in a hard fault. CubeProgrammer cannot read either flash or option bytes. If I try to reset the option bytes anyway, I lose the connection to the MCU completely and it is no longer recognized by CubeProgrammer.

The behavior is not always the same either. On my first attempt, I was able to debug the code several times and see that it works correctly in principle. Resetting the WRP with CubeProgrammer also worked. However, I have now lost my second MCU.

I develop a minimal bootstub for STM32C011J6 and therefore do not use the HAL. Is there an error in the code, that can lead to such a behaviour? 

 

Thank you in advance for any hints or guidance.

 

typedef struct
{
 volatile uint32_t ACR;
 uint32_t RESERVED1;
 volatile uint32_t KEYR;
 volatile uint32_t OPTKEYR;
 volatile uint32_t SR;
 volatile uint32_t CR;
 uint32_t RESERVED2[2];
 volatile uint32_t OPTR;
 volatile uint32_t PCROP1ASR;
 volatile uint32_t PCROP1AER;
 volatile uint32_t WRP1AR;
 volatile uint32_t WRP1BR;
 volatile uint32_t PCROP1BSR;
 volatile uint32_t PCROP1BER;
 uint32_t RESERVED3[17];
 volatile uint32_t SECR;
} FLASH_TypeDef;


#define FLASH_BASE 0x40022000U

#define FLASH_KEY1 0x45670123U
#define FLASH_KEY2 0xCDEF89ABU
#define FLASH_OPT_KEY1 0x08192A3BU
#define FLASH_OPT_KEY2 0x4C5D6E7FU

#define FLASH ((FLASH_TypeDef*)FLASH_BASE)

#define FLASH_CR_OPTSTRT (1U << 17)
#define FLASH_CR_OPTLOCK (1U << 30)
#define FLASH_CR_LOCK (1U << 31)
#define FLASH_SR_BSY1 (1U << 16)
#define FLASH_OPTR_NBOOT_SEL (1U << 24)

#define FLASH_WRP_A_END (0xFFU << 16)
#define FLASH_WRP_A_STRT (0xFFU << 0)

#define GET_FLASH_OPTR_NBOOT_SEL() ((FLASH->OPTR & FLASH_OPTR_NBOOT_SEL) >> 24)
#define GET_FLASH_WRP_A_END() ((FLASH->WRP1AR & FLASH_WRP_A_END) >> 16)
#define GET_FLASH_WRP_A_STRT() ((FLASH->WRP1AR & FLASH_WRP_A_STRT) >> 0)

/**
 * Clears nBOOT_SEL and activates write protection (WRP)
 * for the first page (0x8000000 - 0x8000800) where this
 * bootstub resides.
 */
static void configure_option_bytes(void)
{
 if (GET_FLASH_OPTR_NBOOT_SEL() == 0 &&
 GET_FLASH_WRP_A_STRT() == 0 &&
 GET_FLASH_WRP_A_END() == 0)
 return; // Already configured

 // Unlock FLASH
 FLASH->KEYR = FLASH_KEY1;
 FLASH->KEYR = FLASH_KEY2;

 // Halt here if FLASH is not unlocked
 while (FLASH->CR & FLASH_CR_LOCK);

 // Unlock Option Bytes
 FLASH->OPTKEYR = FLASH_OPT_KEY1;
 FLASH->OPTKEYR = FLASH_OPT_KEY2;

 // Halt here if Option Bytes are not unlocked
 while (FLASH->CR & FLASH_CR_OPTLOCK);

 // Clear nBOOT_SEL bit
 FLASH->OPTR &= ~FLASH_OPTR_NBOOT_SEL;

 // Write protect first page (WRP1A_END = WRP1A_STRT = 0)
 FLASH->WRP1AR = 0;

 // Wait until FLASH not busy
 while (FLASH->SR & FLASH_SR_BSY1);

 // Start Option Bytes programming
 FLASH->CR |= FLASH_CR_OPTSTRT;

 while (FLASH->SR & FLASH_SR_BSY1);

 // Clear OPTSTRT bit after programming
 FLASH->CR &= ~FLASH_CR_OPTSTRT;

 // Lock Option Bytes and FLASH
 FLASH->CR |= FLASH_CR_OPTLOCK;
 FLASH->CR |= FLASH_CR_LOCK;
}