cancel
Showing results for 
Search instead for 
Did you mean: 

SRAM Retention in Standby Mode with STM32G0 Value Line (STM32G0x0) MCU using un-document RRS bit 8 in PWR_CR3 register

Tom MacDonald
Associate III

There are conflicting things written in STM32 documentation regarding SRAM retention during Standby mode with SRM32 G0 MCU.

For example, in RM0454 G0 Reference Manual it states two different things 1 paragraph apart

0693W00000QKsZJQA1.png 

.

The UM2319 G0 HAL/LL Manual has a function which states that it controls SRAM retention during standby functionality:

0693W00000QKsaWQAT.png 

But when I try to compile...

0693W00000QKsabQAD.png 

Looking at the contents of `stm32g0xx_hal_pwr_ex.c` I see that the function I'm trying to access is being excluded from compilation by the pre-processor because the RRS bit is not defined:

0693W00000QKsZeQAL.png 

Looking at the RM0454 G0 Reference Manual again, I see that there is no RRS bit specified in PWR_CR3!

0693W00000QKsbeQAD.png 

A quick google search seems to indicate it's bit 8 that is defined in some header files out there. These header files seemed to be from stm32g03x1 series controllers.... looking at RM0444 G0x1 Reference Manual the plot thickens:

0693W00000QKscrQAD.png 

It would seem the G0x1 "Access" line of micros has this bit defined in its manual but the G0x0 "Value line" data sheet doesn't?

Is that intentional? Is the G0x0 "Value line" microcontroller able to retain its SRAM in standby mode???

Let's test it out!

Added this define to stm32g030xx.h` to get the sram retention HAL function to compile

#define PWR_CR3_RRS_Pos         (8U)
#define PWR_CR3_RRS_Msk         (0x1UL << PWR_CR3_RRS_Pos)
#define PWR_CR3_RRS             PWR_CR3_RRS_Msk

Created a test program to just test SRAM rention my toggling it on and off depending on whether or not the previous runtime's SRAM has been retained or not, and to flash an LED on my custom PCBA depending on the result. This is accomplished by creating a `NOINIT` section in my linkerscript and putting the variable sram_magic_word in it.

Basically app does this:

  • Flash at 1Hz when SRAM retained when expected
  • Flash at 2Hz when SRAM retained when not expected
  • Flash at 10Hz when SRAM not retained
  • Go into standby mode after 5 seconds

__attribute__((section(".app_noinit"))) uint32_t sram_magic_word;
 
int main(void)
{
	/* USER CODE BEGIN 1 */
	/* USER CODE END 1 */
 
	/* MCU Configuration--------------------------------------------------------*/
 
	/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
	HAL_Init();
 
	/* USER CODE BEGIN Init */
	/* USER CODE END Init */
 
	/* Configure the system clock */
	SystemClock_Config();
 
	/* USER CODE BEGIN SysInit */
 
	//We need to configure a pushbutton, an LED (open drain), and a buck converter enable pin
	LL_GPIO_SetPinMode(BUTTON_MCU_GPIO_Port, BUTTON_MCU_Pin, LL_GPIO_MODE_INPUT);
 
	LL_GPIO_InitTypeDef GPIO_InitStruct = {
		.Pin = LED_3_Pin,
		.Mode = LL_GPIO_MODE_OUTPUT,
		.Speed = LL_GPIO_SPEED_FREQ_LOW,
		.OutputType = LL_GPIO_OUTPUT_OPENDRAIN,
		.Pull = LL_GPIO_PULL_NO
	};
	/**/
	LL_GPIO_Init(LED_3_GPIO_Port, &GPIO_InitStruct);
	/*Need to configure buck converter to be on in order to to PCBA revision retrieval*/
	GPIO_InitStruct.Pin = BUCK_EN_Pin;
	GPIO_InitStruct.Mode = LL_GPIO_MODE_OUTPUT;
	GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW;
	GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
	GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
	LL_GPIO_Init(BUCK_EN_GPIO_Port, &GPIO_InitStruct);
 
	#define TEST_SRAM_STANDBY_RETENTION
 
	#ifdef TEST_SRAM_STANDBY_RETENTION
	unsigned int blink_start_ms = uwTick;
 
	//If the bit is indeed controlling SRAM retention, then we would expect that on each button press, we alternate between 1Hz blink for 5 s and 2 Hz blink for 5 s
	//If SRAM retained all the time then we would expect button press to always yield 1 Hz blink for 5 s (on second button press onwards)
 
	//If SRAM was retained when expected, blink for 5 seconds at 1 Hz
	if(sram_magic_word == 0xDEADBEEF){
		sram_magic_word = 0xBADBABEE;
		HAL_PWREx_DisableSRAMRetention();
		LL_GPIO_SetOutputPin(BUCK_EN_GPIO_Port, BUCK_EN_Pin);	//Turn on buck converter to power LED display
		while(uwTick - blink_start_ms < 5000){
			LL_IWDG_ReloadCounter(IWDG);//Pet watchdog so the MCU doesn't reset on us
			LL_GPIO_TogglePin(LED_3_GPIO_Port, LED_3_Pin);
			HAL_Delay(500);
		};
	}
	//If SRAM was retained when not expected, blink for 5 seconds at 2 Hz
	else if (sram_magic_word == 0xBADBABEE){
		sram_magic_word = 0xDEADBEEF;
		HAL_PWREx_EnableSRAMRetention();
		LL_GPIO_SetOutputPin(BUCK_EN_GPIO_Port, BUCK_EN_Pin);	//Turn on buck converter to power LED display
		while(uwTick - blink_start_ms < 5000){
			LL_IWDG_ReloadCounter(IWDG);//Pet watchdog so the MCU doesn't reset on us
			LL_GPIO_TogglePin(LED_3_GPIO_Port, LED_3_Pin);
			HAL_Delay(250);
		};
	}
	//If SRAM variable not retained, blink for 5 seconds at 10 Hz
	else{
		sram_magic_word = 0xDEADBEEF;
		HAL_PWREx_EnableSRAMRetention();
		LL_GPIO_SetOutputPin(BUCK_EN_GPIO_Port, BUCK_EN_Pin);	//Turn on buck converter to power LED display
		while(uwTick - blink_start_ms < 5000){
			LL_IWDG_ReloadCounter(IWDG);//Pet watchdog so the MCU doesn't reset on us
			LL_GPIO_TogglePin(LED_3_GPIO_Port, LED_3_Pin);
			HAL_Delay(100);
		};
	}
	//Turn off buck converter
	LL_GPIO_ResetOutputPin(BUCK_EN_GPIO_Port, BUCK_EN_Pin);
 
	//Code for entering standby mode
 
	HAL_PWR_EnableWakeUpPin(PWR_WAKEUP_PIN2_HIGH);	//Wake up on pushbutton press
	LL_PWR_ClearFlag_WU();	//Need to clear this flag else we wakeup immediately upon entry in standby
	LL_PWR_ClearFlag_SB();	//Need to clear this flag else we wakeup immediately upon entry in standby
	HAL_DBGMCU_DisableDBGStandbyMode(); //Disable debug interface when entering low power mode (to make sure main regulator shuts down?)
	HAL_PWR_EnterSTANDBYMode();	//Enter standby mode (see you next runtime!)
 
	#endif

Note: SRAM gets retained regardless of whether or not the RRS bit is set when you are debugging. That's part of the reason this test app is written this way; so that you can determine when/how SRAM is getting retained without the use of a debugger.

Using the above program with my STM32G030F6, I was able to confirm that YES INDEED, there is an undocumented RSS bit (bit 8) in PWR_CR3 register that controls SRAM retention during standby mode for STM32G0x0 Value Line MCU's.

I think we need a new G0x0 Reference Manual with the correct doucmentation on the PWR_CR3 register!!!

8 REPLIES 8
Piranha
Chief II
KDJEM.1
ST Employee

Hi @Tom MacDonald​ ,

The STM32G0x0 and the STM32G0x1 are based on same silicon. 

Functionality not presented in RM might consequently exist, but they are not guaranteed to be functional.

When your question is answered, please close this topic by choosing Select as Best. This will help other users find that answer faster.

Kaouthar

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.

Coratron
Associate II

So essentially the STM32G0x0 does not have SRAM retention available in standby mode - or in any mode for that matter. This is a shame. I will have to find another use for my chips. We're essentially left with a meager 20 bytes from the RTC backup registers.

@Tom MacDonald​ Your silicon turned out to have a functional SRAM power enabling circuit. It sounds like all units are made as STM32G0x1 at the fab but when QC takes place if it fails any of the extra functions the STM32G0x1 has over the STM32G0x0 definition but the base STM32G0x0 functions are intact then it's branded as STM32G0x0. This is just speculation but it sounds like that's what @KDJEM.1​ meant.

Best friend retention seems to work on my chip since standby mode and stop mode

I have just tested on a Nucleo STM32G071 and SRAM retention works, on my custom board with STM32G070 it does not work so I guess my silicon does not have that portion functional. How many units have you tested this on @Tom MacDonald​ ?

@Tom MacDonald​ Nevemind. It actually works on my silicon too. I don't think I will take the risk for production though, even though I have a feeling it's probably other more advanced functions that are not passing the QC like DAC, etc.

I need to look into the linker file.

If I do the following, then it works - even though I have not defined such ".sram" section in the linker file

__attribute((section(".sram"))) uint8_t runStatus;

If I do the following:

uint8_t runStatus;

Then it does not work. So something is recognising that attribute - I am a bit surprised.

Tom MacDonald
Associate III

haha just re-read my last response. I dictated that to the voice assistant, and it did a pretty hilarious job.

To see if SRAM retention is working or not, you can either change you linkerscript's memory map and startup initialization code to have a "no-init" section somewhere in device ram (probably either at lower addresses than the .bss section or else just have a lower initial stack pointer and have your no-init section located at addresses higher than the stack itself). Then you could output the value over a serial debug terminal to check that it is not being cleared on device reset.

Easier still (if you have a debugger) would be to write a simple program that sets the value of a variable. Then pause debugger, check value of the variable. Then put a breakpoint in the startup routine of your code (i.e. the code located at the RESET vector in the vector table). Then go into standby mode, wake the device back up, and you should now be on a breakpoint before any user code has initialized the RAM. You can check if the SRAM value you set before standby mode is retained or if it has been reset on MCU initialization.

Tom MacDonald
Associate III

Read this to understand all about this process:

https://interrupt.memfault.com/blog/noinit-memory