2026-02-27 4:56 AM - edited 2026-02-27 4:59 AM
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;
}