2023-08-08 09:44 AM
I am new to ST forums. actually, this is my first post here.
I am facing a kind of strange problem with no explanation. actually, I have been digging through the reference manual for 5 hours now.
currently, I am implementing my own version of bare-metal for the embedded flash memory in stm32f407, the problem is that whenever I try to modify options bytes of the flash memory, it behaves as expected but when I power off and then power on my board, the read protection level is always set 1 even if I set it to 0 in the code.
not only that but even if the board
is still connected and I end the debug session after modifying boot options leaving RDP to level 0, when I start a new debugging session, I can't. simply because RDP is set to level 1 by itself.
I actually read in the reference manual page 93 this line:
• Level 1: read protection enabled
It is the default read protection level after option byte erase.
but still don't know what it has to do with RDP level.
here is my code:
HAL_FLASH_ErrStates_t HAL_FLASH_Init()
{
// local used variables
uint16_t local_u16TempVal = 0;
uint8_t local_u32Counter = 0;
uint8_t local_u8TempBitPos = 0;
uint8_t local_u8SectorsLength = sizeof globalConstArr_SectorsConfig_t / sizeof globalConstArr_SectorsConfig_t[0];
HAL_FLASH_ErrStates_t local_errState_t = HAL_FLASH_OK;
// check for errors
for (local_u32Counter = 0; local_u32Counter < local_u8SectorsLength; local_u32Counter++) // if you want to improve code, unroll this for loop for 11 lines of code
{
if (globalConstArr_SectorsConfig_t[local_u32Counter].WriteProtection >= LIB_CONSTANTS_MAX_DRIVER_STATE || globalConstArr_SectorsConfig_t[local_u32Counter].SectorNumber >= HAL_FLASH_MAX_MAIN_MEM_SECTOR)
{
local_errState_t = HAL_FLASH_ERR_INVALID_CONFIG;
break;
}
else
{
// do nothing
}
}
if (globalConstArr_FlashConfig_t[0].DataCacheEnabled >= LIB_CONSTANTS_MAX_DRIVER_STATE || globalConstArr_FlashConfig_t[0].InstructionCacheEnabled >= LIB_CONSTANTS_MAX_DRIVER_STATE || globalConstArr_FlashConfig_t[0].PrefetchEnabled >= LIB_CONSTANTS_MAX_DRIVER_STATE || globalConstArr_FlashConfig_t[0].WaitStates >= HAL_FLASH_MAX_WAIT_STATE || globalConstArr_FlashConfig_t[0].LockConfiguration >= LIB_CONSTANTS_MAX_LOCK_STATE || globalConstArr_FlashConfig_t[0].InterruptsEnabled >= LIB_CONSTANTS_MAX_DRIVER_STATE || globalConstArr_FlashConfig_t[0].ProgramSize >= HAL_FLASH_MAX_PROGRAM_SIZE || globalConstArr_FlashConfig_t[0].ReadProtectionLevel >= HAL_FLASH_MAX_READ_PROTECT_LVL || globalConstArr_MiscellaneousConfig_t[0].ResetOnStandBy >= LIB_CONSTANTS_MAX_DRIVER_STATE || globalConstArr_MiscellaneousConfig_t[0].ResetOnStop >= LIB_CONSTANTS_MAX_DRIVER_STATE || globalConstArr_MiscellaneousConfig_t[0].IndependentWatchDogType >= HAL_FLASH_MAX_INDPEND_WATCH_DOG_TYPE || globalConstArr_MiscellaneousConfig_t[0].BrownoutResetLevel >= HAL_FLASH_MAX_BROWN_RESET_LVL)
{
local_errState_t = HAL_FLASH_ERR_INVALID_CONFIG;
}
else
{
// do nothing
}
// check for busy wait or not
local_errState_t = HAL_FLASH_GetHardwareErrors();
if (local_errState_t == HAL_FLASH_ERR_FLASH_BUSY && globalConstArr_FlashConfig_t[0].InterruptsEnabled == LIB_CONSTANTS_DISABLED)
{
// busy wait
while (LIB_MATH_BTT_GET_BIT(global_pFlashReg_t->FLASH_SR, HAL_FLASH_SR_BSY) == 1)
{
};
local_errState_t = HAL_FLASH_OK;
}
// main function
if (local_errState_t == HAL_FLASH_OK)
{
// unlock all configuration registers
global_pFlashReg_t->FLASH_KEYR = HAL_FLASH_CR_KEY1;
global_pFlashReg_t->FLASH_KEYR = HAL_FLASH_CR_KEY2;
global_pFlashReg_t->FLASH_OPTKEYR = HAL_FLASH_OPTCR_OPTKEY1;
global_pFlashReg_t->FLASH_OPTKEYR = HAL_FLASH_OPTCR_OPTKEY2;
// assign global configuration variables
global_u8BehaviorType = globalConstArr_FlashConfig_t[0].InterruptsEnabled == LIB_CONSTANTS_ENABLED ? HAL_FLASH_CONFIG_VAL_OPERATION_TYPE_INTERRUPT : HAL_FLASH_CONFIG_VAL_OPERATION_TYPE_BLOCKING;
// configure flash & sectors
LIB_MATH_BTT_ASSIGN_BIT(global_pFlashReg_t->FLASH_ACR, HAL_FLASH_ACR_DCEN, globalConstArr_FlashConfig_t[0].DataCacheEnabled);
LIB_MATH_BTT_ASSIGN_BIT(global_pFlashReg_t->FLASH_ACR, HAL_FLASH_ACR_ICEN, globalConstArr_FlashConfig_t[0].InstructionCacheEnabled);
LIB_MATH_BTT_ASSIGN_BIT(global_pFlashReg_t->FLASH_ACR, HAL_FLASH_ACR_PRFTEN, globalConstArr_FlashConfig_t[0].PrefetchEnabled);
LIB_MATH_BTT_ASSIGN_BITS(global_pFlashReg_t->FLASH_ACR, HAL_FLASH_ACR_LATENCY, globalConstArr_FlashConfig_t[0].WaitStates, 3);
LIB_MATH_BTT_ASSIGN_BIT(global_pFlashReg_t->FLASH_CR, HAL_FLASH_CR_ERRIE, globalConstArr_FlashConfig_t[0].InterruptsEnabled);
LIB_MATH_BTT_ASSIGN_BIT(global_pFlashReg_t->FLASH_CR, HAL_FLASH_CR_EOPIE, globalConstArr_FlashConfig_t[0].InterruptsEnabled);
LIB_MATH_BTT_ASSIGN_BITS(global_pFlashReg_t->FLASH_CR, HAL_FLASH_CR_PSIZE, globalConstArr_FlashConfig_t[0].ProgramSize, 2);
for (local_u32Counter = 0; local_u32Counter < local_u8SectorsLength; local_u32Counter++) // if you want to improve code, unroll this for loop for 11 lines of code
{
local_u8TempBitPos = LIB_MATH_BTT_u8GetMSBSetPos(globalConstArr_SectorsConfig_t[local_u32Counter].SectorNumber);
local_u16TempVal |= (!globalConstArr_SectorsConfig_t[local_u32Counter].WriteProtection << local_u8TempBitPos);
}
LIB_MATH_BTT_ASSIGN_BITS(global_pFlashReg_t->FLASH_OPTCR, HAL_FLASH_OPTCR_nWRP, local_u16TempVal, 12);
LIB_MATH_BTT_ASSIGN_BIT(global_pFlashReg_t->FLASH_OPTCR, HAL_FLASH_OPTCR_nRST_STDBY, !globalConstArr_MiscellaneousConfig_t[0].ResetOnStandBy);
LIB_MATH_BTT_ASSIGN_BIT(global_pFlashReg_t->FLASH_OPTCR, HAL_FLASH_OPTCR_nRST_STOP, !globalConstArr_MiscellaneousConfig_t[0].ResetOnStop);
LIB_MATH_BTT_ASSIGN_BIT(global_pFlashReg_t->FLASH_OPTCR, HAL_FLASH_OPTCR_WDG_SW, globalConstArr_MiscellaneousConfig_t[0].IndependentWatchDogType);
LIB_MATH_BTT_ASSIGN_BITS(global_pFlashReg_t->FLASH_OPTCR, HAL_FLASH_OPTCR_BOR_LEV, globalConstArr_MiscellaneousConfig_t[0].BrownoutResetLevel, 2);
LIB_MATH_BTT_ASSIGN_BITS(global_pFlashReg_t->FLASH_OPTCR, HAL_FLASH_OPTCR_RDP, globalConstArr_FlashConfig_t[0].ReadProtectionLevel, 8);
// lock configuration if configured
LIB_MATH_BTT_ASSIGN_BIT(global_pFlashReg_t->FLASH_CR, HAL_FLASH_CR_LOCK, globalConstArr_FlashConfig_t[0].LockConfiguration);
LIB_MATH_BTT_ASSIGN_BIT(global_pFlashReg_t->FLASH_OPTCR, HAL_FLASH_OPTCR_OPTLOCK, globalConstArr_FlashConfig_t[0].LockConfiguration);
// save the values
LIB_MATH_BTT_SET_BIT(global_pFlashReg_t->FLASH_OPTCR, HAL_FLASH_OPTCR_OPTSTRT);
while (LIB_MATH_BTT_GET_BIT(global_pFlashReg_t->FLASH_SR, HAL_FLASH_SR_BSY) == 1)
{
};
// check for errors
local_errState_t = HAL_FLASH_GetHardwareErrors();
if (local_errState_t == HAL_FLASH_ERR_FLASH_BUSY && globalConstArr_FlashConfig_t[0].InterruptsEnabled == LIB_CONSTANTS_DISABLED)
{
// busy wait
while (LIB_MATH_BTT_GET_BIT(global_pFlashReg_t->FLASH_SR, HAL_FLASH_SR_BSY) == 1)
{
};
local_errState_t = HAL_FLASH_OK;
}
local_errState_t = HAL_FLASH_ERR_FLASH_BUSY ? HAL_FLASH_OK : local_errState_t;
}
return local_errState_t;
}
PS: the problem is solved when I comment below these lines which are responsible for saving option values:
// save the values
LIB_MATH_BTT_SET_BIT(global_pFlashReg_t->FLASH_OPTCR, HAL_FLASH_OPTCR_OPTSTRT);
while (LIB_MATH_BTT_GET_BIT(global_pFlashReg_t->FLASH_SR, HAL_FLASH_SR_BSY) == 1)
{
};
2023-08-08 10:11 AM
Huh?
is this some kind of advertisement?
and yes I am pretty sure everything goes well before reset (I made sure every register has the expected value before going to reset) but after the reset, RDP simply just equals 1 because I modified option bytes before reset.
2023-08-08 10:31 AM
(Yes, the previous reply was spam. Just report and ignore.)
Show a screenshot of the contents of the FLASH_OPTCR register just prior to the line where you set HAL_FLASH_OPTCR_OPTSTRT.
There aren't any mechanisms for getting to RDP level 1 without modifying the option bytes and applying via the OPTSTRT bit.
2023-08-08 11:00 AM
This type of bit-level manipulation of volatile peripheral register surely must generate a massive amount of unnecessary load/store code or interactions. Bare metal's goal is to simplify to a minimal number of interactions, no?
2023-08-09 07:41 AM
sorry for the late reply.
Before executing the line where I set HAL_FLASH_OPTCR_OPTSTRT:
After Executing the line where I set HAL_FLASH_OPTCR_OPTSTRT:
After Executing wait instruction for Busy flag to be cleared:
2023-08-09 07:53 AM
oh, almost forget, after the end of debug session, if I tried to open a new debug session or burn the code, here is what I got:
and if I tried to connect to the board using the ST-Link utility, here is what I got:
so in order to return back to RDP = level 0, I click on Target->option bytes->select Level 0 and then Apply.
2023-08-09 09:45 AM
Not real sure, but note that setting WDG_SW=0 will cause resets unless the watchdog is refreshed. Could be the watchdog resetting things before an operation completes. I would keep that at 1 during debugging.
2023-08-09 09:50 AM
I tried and changed WDG_SW back to 1 and still have the same problem, it has been more than a day working on this problem and I don't know why this strange behavior that's not mentioned in any application note or the manual.
2023-08-09 12:09 PM - edited 2023-08-09 12:10 PM
You have a lot of code there that I'm not wading into. Might want to look at HAL functions working and compare what you're doing with what those are doing at the register level. If you can replicate it with HAL, probably will have more interest.
It's easy to blame the silicon or some weird behavior, but the answer is usually more boring than that. These chips are super old and super popular. If they were going into RDP level 1 spuriously, we would see more reports.