2021-11-17 02:32 PM
Hi,
I'm trying to make SRAM2a retention in standby mode work on my STM32WB55 device.
As far as I can tell, the device enters and gets out of Standby as expected (the C1SBF and C2SBF flags are appropriately set when the MCU get sout of the low power state).
I've reasonably certain of my variable being in the right SRAM bank (the debugger shows its address is 0x200300000, which is the start of SRAM2a as expected).
However, even after making sure the RRS bit in PWR_CR3 is set, and checking that the varible is appropriately initialized before entering Standby, I still get its value back to zero after the device wakes up...
My device is powered with all its power supply pins (even VBAT) to 3.3V, no SMPS.
Linker script and startup code are directly from STM32CubeMX generation with the latest firmware package (STM32Cube_FW_WB_V1.12.1)
Any ideas ? Obvious errors ? Thanks in advance.
/**
* @brief Function to configure and enter in Standby Mode.
* @param None
* @retval None
*/
void EnterStandbyMode(void)
{
/* Specific procedure on STM32WB, in case of initial power-up and RF stack no started */
/* Note: This procedure is required when user application wants to request */
/* a low-power mode in the particular case: */
/* - RF stack not started: On STM32WB, system low-power mode is fixed */
/* by the deepest low-power modes of each sub-system (CPU1, */
/* CPU2, RF). */
/* Standard case is RF stack started and managing low-power modes */
/* of CPU2 and RF. */
/* In case of RF stack not started, CPU2 low-power mode must be */
/* forced to the lowest level. This allows to require all system */
/* low-power modes using only PWR for CPU1. */
/* low-power mode. */
/* - Initial power-up: In case of power-on reset, CPU2 low-power mode */
/* has its reset value and must be set. */
/* In case of system is resumed from low-power mode standby */
/* or shutdown, configuration of PWR parameters related to CPU2 are */
/* retained and must not modified (This check is required in case */
/* of RF stack started afterwards and to not overwritte its */
/* low-power configuration). */
if( (LL_PWR_IsActiveFlag_C1SB() == 0)
|| (LL_PWR_IsActiveFlag_C2SB() == 0)
)
{
/* Set the lowest low-power mode for CPU2: shutdown mode */
LL_C2_PWR_SetPowerMode(LL_PWR_MODE_SHUTDOWN);
}
/* Check and Clear the Wakeup flag */
if (LL_PWR_IsActiveFlag_WU2() != 0)
{
LL_PWR_ClearFlag_WU2();
}
if (LL_PWR_IsActiveFlag_WU5() != 0)
{
LL_PWR_ClearFlag_WU5();
}
power_usb_init(true);
/* Wait that user release the User push-button (SW1) */
while(button_hal_get_state() == 1){}
HAL_PWREx_EnableSRAMRetention();
/* Disable all used wakeup sources */
LL_PWR_DisableWakeUpPin(LL_PWR_WAKEUP_PIN2);
LL_PWR_DisableWakeUpPin(LL_PWR_WAKEUP_PIN5);
/* Clear all wake up Flag */
LL_PWR_ClearFlag_WU();
// /* Enable pull-up and pull-down configuration for CPU1 */
LL_PWR_EnablePUPDCfg();
/* Set wakeup pin polarity */
LL_PWR_SetWakeUpPinPolarityLow(LL_PWR_WAKEUP_PIN2);
LL_PWR_SetWakeUpPinPolarityHigh(LL_PWR_WAKEUP_PIN5);
/* Enable wakeup pin */
LL_PWR_EnableWakeUpPin(LL_PWR_WAKEUP_PIN2);
LL_PWR_EnableWakeUpPin(LL_PWR_WAKEUP_PIN5);
/* As default User push-button (SW1) state is high level, need to clear all wake up Flag again */
LL_PWR_ClearFlag_WU();
HAL_PWR_EnterSTANDBYMode();
}
#define SHARED_NOINIT __attribute__((section ("MB_MEM1"))) __attribute__((aligned(4))) static // Place variable in SRAM2a
SHARED_NOINIT uint32_t blah_noinit;
/**
* @brief The application entry point.
* @retval int
*/
int main(void) {
/* Check if the system was resumed from Standby mode */
/* Note: On STM32WB, both CPU1 and CPU2 must be in Standby mode to set the entire system in Standby mode */
if ((LL_PWR_IsActiveFlag_C1SB() != 0) && (LL_PWR_IsActiveFlag_C2SB() != 0)) {
/* Clear Standby flag */
LL_PWR_ClearFlag_C1STOP_C1STB();
LL_PWR_ClearFlag_C1STOP_C1STB();
power_usb_init(true);
led_hal_init(true);
if ( blah_noinit == 0xBADBEEF){
led_hal_set_green(true);
} else {
led_hal_set_red(true);
}
while (true);
}
HAL_DBGMCU_EnableDBGStandbyMode();
blah_noinit = 0xBADBEEF;
// ... rest of the application...
Solved! Go to Solution.
2021-11-18 08:39 AM
It seems I found the problem here (search function of the forum and Google both didn't find it yesterday... :/)
So my code above doesn't have any problem in itself. It's only a problem with the SRAM2_RST bit in Flash register OPTR, that was set to 0.
Bit 25 SRAM2_RST: SRAM2 and PKA RAM Erase when system reset
0: SRAM2 and PKA RAM erased when a system reset occurs
1: SRAM2 and non-secure PKA RAM not erased when a system reset occurs
This bit is part of the Option Bytes, and can be set either with an application like STM32CubeProgrammer ("OB" tab), or programatically.
In my case, programming it is a better option for production, so here is the code I use.
One important detail is that even after this bit has been changed by this code, the change will only take effect after a Power-On-Reset.
static bool sram2_can_be_retained_after_standby = true;
/*
* Option Bytes are a special part of the FLASH controlling BOOT options.
* We need Option Byte SRAM2_RST in Flash OPTR to 1 to prevent SRAM2 erasure after Standby
* This change can only be seen AFTER A Power-On-Reset.
*/
void check_option_byte_sram2_no_reset(){
FLASH_OBProgramInitTypeDef ob_conf;
HAL_FLASHEx_OBGetConfig(&ob_conf); // get current config
if ( !( ob_conf.UserConfig & OB_SRAM2_RST_NOT_ERASE) ){ // ignore if bit already set
// regardless of success of the change below, the current config will stay
// active until the next power cycle
sram2_can_be_retained_after_standby = false;
// Unlock the Flash to enable the flash control register access
HAL_FLASH_Unlock();
/* Clear OPTVERR bit set on virgin samples */
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_OPTVERR);
FLASH_OBProgramInitTypeDef ob_init = {0};
ob_init.OptionType = OPTIONBYTE_USER;
ob_init.UserType = OB_USER_SRAM2RST;
ob_init.UserConfig = OB_SRAM2_RST_NOT_ERASE;
if (HAL_FLASH_OB_Unlock() == HAL_OK){ // Unlock Option Bytes
HAL_FLASHEx_OBProgram(&ob_init);
}
HAL_FLASH_OB_Lock();
HAL_FLASH_Lock();
}
}
Cheers,
Nicolas
2021-11-17 02:36 PM
2021-11-17 02:37 PM
2021-11-18 08:39 AM
It seems I found the problem here (search function of the forum and Google both didn't find it yesterday... :/)
So my code above doesn't have any problem in itself. It's only a problem with the SRAM2_RST bit in Flash register OPTR, that was set to 0.
Bit 25 SRAM2_RST: SRAM2 and PKA RAM Erase when system reset
0: SRAM2 and PKA RAM erased when a system reset occurs
1: SRAM2 and non-secure PKA RAM not erased when a system reset occurs
This bit is part of the Option Bytes, and can be set either with an application like STM32CubeProgrammer ("OB" tab), or programatically.
In my case, programming it is a better option for production, so here is the code I use.
One important detail is that even after this bit has been changed by this code, the change will only take effect after a Power-On-Reset.
static bool sram2_can_be_retained_after_standby = true;
/*
* Option Bytes are a special part of the FLASH controlling BOOT options.
* We need Option Byte SRAM2_RST in Flash OPTR to 1 to prevent SRAM2 erasure after Standby
* This change can only be seen AFTER A Power-On-Reset.
*/
void check_option_byte_sram2_no_reset(){
FLASH_OBProgramInitTypeDef ob_conf;
HAL_FLASHEx_OBGetConfig(&ob_conf); // get current config
if ( !( ob_conf.UserConfig & OB_SRAM2_RST_NOT_ERASE) ){ // ignore if bit already set
// regardless of success of the change below, the current config will stay
// active until the next power cycle
sram2_can_be_retained_after_standby = false;
// Unlock the Flash to enable the flash control register access
HAL_FLASH_Unlock();
/* Clear OPTVERR bit set on virgin samples */
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_OPTVERR);
FLASH_OBProgramInitTypeDef ob_init = {0};
ob_init.OptionType = OPTIONBYTE_USER;
ob_init.UserType = OB_USER_SRAM2RST;
ob_init.UserConfig = OB_SRAM2_RST_NOT_ERASE;
if (HAL_FLASH_OB_Unlock() == HAL_OK){ // Unlock Option Bytes
HAL_FLASHEx_OBProgram(&ob_init);
}
HAL_FLASH_OB_Lock();
HAL_FLASH_Lock();
}
}
Cheers,
Nicolas