This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

.noinit variable value not retained after sys off

I'm using SDK 12.1.0, gcc, nRF51822, no SD init'ed or enabled at the time this code is running. I need to retain the values of a bunch of variables across a sys off.

Here's my test variable:

static int8_t retained_ram_test_int __attribute__ ((section(".noinit")));

and test function:

printf("Retained RAM test.\n");

uint32_t gp_reg = NRF_POWER->GPREGRET;

bool started_from_test = (gp_reg == START_FROM_TEST);

NRF_POWER->GPREGRET = 0x00000000UL;

if (started_from_test)
{
	printf("After sys off. Retained RAM value: %d.\n", retained_ram_test_int);

	printf("Done. Did we see a value > 0?\n");

	while (true)
	{
		__WFE();
	}
}

printf("Before sys off. Writing to value in retained RAM.\n");

// Retain RAM. This is NOT the method used by the <SDK>/examples/peripheral/ram_retention application, it's one from this post:
//   devzone.nordicsemi.com/.../
NRF_POWER->RAMON    = POWER_RAMON_OFFRAM0_RAM0On << POWER_RAMON_OFFRAM0_Pos
					| POWER_RAMON_OFFRAM1_RAM1On << POWER_RAMON_OFFRAM1_Pos
					| POWER_RAMON_ONRAM0_RAM0On << POWER_RAMON_ONRAM0_Pos
					| POWER_RAMON_ONRAM1_RAM1On << POWER_RAMON_ONRAM1_Pos;

NRF_POWER->RAMONB   = POWER_RAMONB_OFFRAM2_RAM2On << POWER_RAMONB_OFFRAM2_Pos
					| POWER_RAMONB_OFFRAM3_RAM3On << POWER_RAMONB_OFFRAM3_Pos
					| POWER_RAMONB_ONRAM2_RAM2On << POWER_RAMONB_ONRAM2_Pos
					| POWER_RAMONB_ONRAM3_RAM3On << POWER_RAMONB_ONRAM3_Pos;

retained_ram_test_int = 1;

// Wake on motion.
printf("Programming accelerometer for alerting phase 1.\n");
acc_kionix_init();
acc_kionix_program(KIONIX_MODE_ALERTING_PHASE_1);
acc_kionix_clear_interrupt(NULL, 0);
nrf_gpio_cfg_sense_input(PIN_KX_INT, NRF_GPIO_PIN_NOPULL, NRF_GPIO_PIN_SENSE_HIGH);

printf("Going into sys off. Shake me to wake me, then continue in gdb.\n");
DEBUG_LED_OFF_ALL();
DEBUG_LED_ON(LED_SYSTEM_OFF);
nrf_delay_ms(100);
NRF_POWER->GPREGRET = START_FROM_TEST;
NRF_POWER->SYSTEMOFF = 1;

// Should be unreachable code:
while (true)
{
	__WFE();
}

The acc_* functions are an accelerometer driver that just fires an interrupt to wake up the nRF51822.

Here's my linker script:

SEARCH_DIR(.)
GROUP(-lgcc -lc -lnosys)

MEMORY
{
  FLASH (rx) :                ORIGIN = 0x1B000,    LENGTH = 0x21C00

  RAM (rwx) :                 ORIGIN = 0x20002008, LENGTH = 0x5FF8

  NOINIT (rwx) :  ORIGIN = 0x20007F5C, LENGTH = 0xA4

  BOOTLOADER_SETTINGS (rw) : ORIGIN = 0x0003FC00, LENGTH = 0x0400

  UICR_BOOTLOADER (r) : ORIGIN = 0x10001014, LENGTH = 0x04
}

SECTIONS
{
  .bootloaderSettings(NOLOAD) :
  {

  } > BOOTLOADER_SETTINGS

  .uicrBootStartAddress :
  {
    KEEP(*(.uicrBootStartAddress))
  } > UICR_BOOTLOADER

  .noinit(NOLOAD) :
  {
    *(.noinit*)
  } > NOINIT
}

SECTIONS
{
  .fs_data :
  {
    PROVIDE(__start_fs_data = .);
    KEEP(*(.fs_data))
    PROVIDE(__stop_fs_data = .);
  } > RAM
} INSERT AFTER .data;

INCLUDE "nrf51_common.ld"

I use the stock gcc_startup_nRF51.S file from the SDK. The test fails. Output:

main()
Retained RAM test.
Before sys off. Writing to value in retained RAM.
Programming accelerometer for alerting phase 1.
Going into sys off. Shake me to wake me, then continue in gdb.



main()
Retained RAM test.
After sys off. Retained RAM value: 0.
Done. Did we see a value > 0?

I've read this:

devzone.nordicsemi.com/.../

When gdb breaks at the ResetHandler, it's not possible to read the value of retained_ram_test_int or step through the ResetHandler line by line. If I try to step, I end up on the first line of main(), by which time my variable is already 0.

Related