cancel
Showing results for 
Search instead for 
Did you mean: 

Setting Read Protection level 1 from firmware

alexndre
Associate II

 

I have tried following the examples in the reference manual and online, but am having issues!

This is on STM32F030C8T6, on a custom PCB and connected to debugger over SWD:

 

 

void readProtect_lvl1(void){
   //read protection is in effect on next power cycle
   while ((FLASH->SR & FLASH_SR_BSY) != 0)	{} //wait for any ongoing flash operation to complete
   if ((FLASH->CR & FLASH_CR_LOCK) != 0)
   {
   FLASH->KEYR = 0x45670123UL; //magic number removes control register lock
   FLASH->KEYR = 0xCDEF89ABUL; //magic number removes control register lock
   }
   while ((FLASH->SR & FLASH_SR_BSY) != 0)	{} //wait for flash operation to complete
   if ((FLASH->CR & FLASH_CR_OPTWRE) == 0)
   {
   FLASH->OPTKEYR = 0x45670123UL; //magic number sets option byte write access
   FLASH->OPTKEYR = 0xCDEF89ABUL; //magic number sets option byte write access
   }
   FLASH->CR |= FLASH_CR_OPTER; // must erase option byte first
   FLASH->CR |= FLASH_CR_STRT; //start flash again
   while ((FLASH->SR & FLASH_SR_BSY) != 0)	{}
   while ((FLASH->SR & FLASH_SR_EOP) == 0) {}; //wait for end of operation
   FLASH->SR |= FLASH_SR_EOP; //clear end of operation flag
   FLASH->CR &= ~FLASH_CR_OPTER; //clear erase bit
   FLASH->CR |= FLASH_CR_OPTPG; // set programming bit !!PGERR (FLASH_CR_bit2)!!
   OB->RDP = 0xBB; //any value other than 0xCC or 0xAA sets lvl1 read  protection !!after this operation, OB->RDP = 0xfe01 !!
   FLASH->CR &= ~FLASH_CR_OPTPG; // reset option byte programming bit 
   FLASH->CR |= FLASH_CR_LOCK; // reset the control register lock bit
};

 

 

some notes from debugging:

- good: flash key sequence clears FLASH_CR_LOCK 

-good: flash option key sequence sets write enable OPT_WRE 

-good: FLASH_CR_OPTER resets option byte to 0xFFFF

-good: clearing FLASH_CR_OPTER, no errors (looking at flash status register, PGERR is not set)

-first problem: setting FLASH_CR_OPTPG does work (bit changes), but PGERR flag is set (flash status register)

-second problem: after "OB->RDP = 0xBB" operation, the result after that line executes is: OB->RDP = 0xfe01, is one bit is getting in, the complement is set by hardware during programming and then it seems the RDP byte locks?

 

I'm still achieving lvl1 read protection, (since any value other than 0xAA or 0xCC sets lvl1), however I would like to understand what I'm doing wrong! Thank you for your help

1 ACCEPTED SOLUTION

Accepted Solutions
STea
ST Employee

Hello @alexndre ,

You can refer to this article How to program STM32 Option Bytes with the HAL API - STMicroelectronics Communityin which you will find section 2  Setting RDP Level using the HAL API .

BR

In order 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.

View solution in original post

9 REPLIES 9
alexndre
Associate II
 OB->RDP = 0xBB; //any value other than 0xCC or 0xAA sets lvl1 read protection
    while ((FLASH->SR & FLASH_SR_BSY) != 0) {}
    FLASH->CR &= ~FLASH_CR_OPTPG; //reset option byte programming bit
    FLASH->CR |= FLASH_CR_LOCK; //reset the control register lock bit
};

suspect: OB->RDP = 0xBB is in progress, but the following line immediately clears the programming bit, so interrupts the flash programming operation.

tried adding the FLASH_SR_BUSY check, but the same result, RDP = 0xFE.

(also, this error is occurring with single step mode during debugging, so the lines after OB->RDP = 0xBB should have no effect during these tests)

TDK
Guru

Here's what HAL does.

stm32f0xx_hal_driver/Src/stm32f0xx_hal_flash_ex.c at f3946cb6e841a78f56c5a02c4bbf819f770d117d · STMicroelectronics/stm32f0xx_hal_driver (github.com)

Looks like you do about the same except that you don't wait for the operation on OB->RDP to finish (by waiting for BSY to clear or EOP to set). Could be the issue.

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

Hello @alexndre ,

You can refer to this article How to program STM32 Option Bytes with the HAL API - STMicroelectronics Communityin which you will find section 2  Setting RDP Level using the HAL API .

BR

In order 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.
alexndre
Associate II

for the googlers of the future: this works! Thanks for all the replies, copying HAL was key (HAL is better)

for whatever reason, the flash status register no longer shows a PGERR as FLASH->CR |= FLASH_CR_OPTPG executes in debug mode

results are consistent across 3 different boards, as was the original bug

the routine was called at the end of a self-test mode (bed of nails routine), so the clocks were initialized etc. - unsure what was going on. also tried running the routine first thing after setup, with the same PGERR occuring.

 

void setReadProtection(bool lvl){
    //read protection is in effect on next power cycle
    while ((FLASH->SR & FLASH_SR_BSY) != 0)	{} //wait for any ongoing flash operation to complete
    if ((FLASH->CR & FLASH_CR_LOCK) != 0)
    {
        FLASH->KEYR = 0x45670123UL; //magic number removes control register lock
        FLASH->KEYR = 0xCDEF89ABUL; //magic number removes control register lock
    }
    while ((FLASH->SR & FLASH_SR_BSY) != 0)	{} //wait for flash operation to complete
    if ((FLASH->CR & FLASH_CR_OPTWRE) == 0)
    {
        FLASH->OPTKEYR = 0x45670123UL; //magic number sets option byte write access
        FLASH->OPTKEYR = 0xCDEF89ABUL; //magic number sets option byte write access
    }
    FLASH->CR |= FLASH_CR_OPTER; //must erase option byte first
    FLASH->CR |= FLASH_CR_STRT; //start flash again
    while ((FLASH->SR & FLASH_SR_BSY) != 0)	{} //wait for operation
    FLASH->CR &= ~FLASH_CR_OPTER; //clear erase bit
    FLASH->CR |= FLASH_CR_OPTPG; //set programming bit
    if(lvl == 0){
        OB->RDP = (uint8_t)0xAA; //lvl 0 RDP @ OBJ->RDP=0xAA
    }else{
        OB->RDP = (uint8_t)0xBB; //any value other than 0xCC or 0xAA sets lvl1 read protection
    }
    while ((FLASH->SR & FLASH_SR_BSY) != 0) {} //wait for operation
    FLASH->CR &= ~FLASH_CR_OPTPG; //reset option byte programming bit
    FLASH->CR |= FLASH_CR_LOCK; //reset the control register lock bit
};

 

 

Hi @alexndre ,

The difference between the code in your latest post and the code in OP is the check for FLASH_SR_BSY after writing the OB_RDP byte, correct?

But you've already did that in your second post, haven't you?

So, this does not really explain, why you had the problem previously and what step did exactly "solve" it.

JW

 

Perhaps better to report progress via telemetry than try to single step in the debugger, which is apt to be invasive.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

And that indeed may have made the difference. Hard to assess, given most debuggers are opaque.

JW

alexndre
Associate II

for understanding, I have copied the code from the first post, and now completes successfully (PRGERR is never set as OPTPG is set during debug, and after line step the result is 0x44bb in ob->RDP), so can't recreate the issue

cant find out what was the culprit, same debug equipment and everything (though i have seen one other thread with the exact same issue, where the PRGERR occurs during OPTPG set, and 0x01 is set to RDP later)

I've been building 50 units, and can see that the first twenty or so all have read protection, but the byte value is 0x01.

not sure what exactly changed, kind of baffled

if anyone else has this problem, I am using the cheap stlink v2 clones found on aliexpress - I wouldn't blame them though, i'm sure they can SWD as good as anything else. I am running at 1800 kHz which is slower than the default 4000.

Those 50 units, did you run the RDP-locking program on all of them while the debugger was connected?

The difference might be as inconspicuous as having open/closed some registers' view in the debugger...

JW