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

Retain RTC during soft reset

I'm working on a battery powered system which needs to keep track of an absolute time stamp. So I need the RTC module and some kind of energy saving mode. As the RTC is not running in System Off I use the System On sleep mode when Idle.

To decrease the current consumption in sleep mode, I also disable RAM beforehand. I noticed that I need to keep RAM Block3 enabled to be able to wake up again (I guess because it contains the Stack, right?) However, the content of RAM Blocks 0,1,2 is not useable after wake up, so I perform a soft reset. Problem is that this resets the RTC COUNTER register. Is there a possibility to retain this register?

I was also thinking about making the compiler use RAM Block 3 for a part of my code, which then will still be usable after wake up and where I would save the counter value before resetting. I think I need to change the linker script but I couldn't find how exactly. Any ideas? (I'm using GCC 5.3.0)

I'm also using soft device S110, which I disable before entering sleep mode. Here's the code snippet where sleep mode is initiated:

sd_softdevice_disable();

// Disable RAM-Blocks 0,1,2 (Block 3 must stay enabled as it contains the Stack)
NRF_POWER->RAMON	= POWER_RAMON_OFFRAM0_RAM0Off << POWER_RAMON_OFFRAM0_Pos
                    | POWER_RAMON_OFFRAM1_RAM1Off << POWER_RAMON_OFFRAM1_Pos
                    | POWER_RAMON_ONRAM0_RAM0Off << POWER_RAMON_ONRAM0_Pos
                    | POWER_RAMON_ONRAM1_RAM1Off << POWER_RAMON_ONRAM1_Pos;

NRF_POWER->RAMONB	= POWER_RAMONB_OFFRAM2_RAM2Off << POWER_RAMONB_OFFRAM2_Pos
                    | POWER_RAMONB_OFFRAM3_RAM3Off << POWER_RAMONB_OFFRAM3_Pos
                    | POWER_RAMONB_ONRAM2_RAM2Off << POWER_RAMONB_ONRAM2_Pos
                    | POWER_RAMONB_ONRAM3_RAM3On << POWER_RAMONB_ONRAM3_Pos;


__set_PRIMASK(1);	// prevent execution of isr when waking up
__WFI();			// enter sleep mode

/* RAMON and RAMONB Registers are retained. Therefore RAM needs to be enabled
   prior to soft reset in order to make it accessible for the next startup. */
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;

NVIC_SystemReset(); // Perform soft reset because content of RAM was lost during sleep mode
  • I think you don't need a reset, but you need the behavior of the reset handler. I think you can just call it right after you enabled the ram again. This will reinitialise the ram content, but keep the rtc running.

  • Hi Martijn, thanks for your comment. I replaced NVIC_SystemReset() with Reset_Handler() and it basically works. But the first call of sd_nvic_critical_region_enter(0) after the "reset" crashes with the SIGTRAP signal. Could it be that the SVC_Handler is somehow corrupted after the Reset_Handler() call?

  • Ah, you call the reset handler of you application, which calls the reset handler of the application and resets the ram content of the application.

    But it skips the reset_handler of the mbr and softdevice, so the softdevice ram content is still corrupted. I don't know whether this is possible, but maybe you can set the Reset_Handler pending via NVIC? or maybe you can get the reset_handler address of the MBR(located at address 0x4) and call that so the full chain of MBR -> softdevice -> application reset handlers is called without a reset.

  • In startup_nrf51x.c I have:

    void * g_pfnVectors[0x30] __attribute__ ((section (".isr_vector"))) = 
    {
    	&_estack,
    	&Reset_Handler,
    	&NMI_Handler,
    	&HardFault_Handler,
    	NULL,
    	NULL,
    	...,
    ...
    }
    

    Doesn't this mean that reset_handler address of the MBR(located at address 0x4) is exactly what I call with Reset_Handler()? I think the isr_vector is placed at address 0x00 with alignment 0x04 as described in the Cortex M0 Manual

    I don't see the Stack being initialized. Do I maybe also have to reset the SP manually as it is normally done by the reset?

  • The cortex-m0 core only uses the vector table placed at address 0x0. but there a multiple vector tables when you use a softdevice. The MBR has a vector table @ address 0x0. The softdevice has a vector table right after the MBR and the application has a vector table right after the softdevice. The MBR simply looks through the vector tables of the softdevice and application and jumps to the correct address.

    When you call Reset_Handler() in you application you jump the Reset_Handler in you application space and skip the MBR version and softdevice version.

Related