How to use the internal RTC on nRF52833 SoC to keep system time across reboots

Hello,

I need your help on how to use the internal RTC on nRF52833 SoC to keep the system time under zypher.

I need the RTC to keep its time after,

1- Reboots

2- Sleep using k_sleep( Duration ) 

3- System Off mode, although this use case may not be necessary but still interested if it is possible.

Finally, looking at the nRF52833 RTC registers I could not find a way of setting the time. Is there one?

Kind regards

Mohamed

Parents
  • Thank you.

    I would appreciate it a great deal if you could point me to an example showing how to the persistent registers.

    Also, what does the first line in red mean?

    This information applies to the following SoftDevices: S130, S132, S332

    Note, I am using,

    - nRF52833 SoC

    - SEGGER Embedded Studio for ARM
      Release 5.60  Build 2021081102.47262
      Nordic Edition
      Windows x64

    - Zephyr OS build v2.6.99-ncs1

    - NCS v1.7.0

    Kind regards

    Mohamed

  • Hi Susheel,

    Thank you.

    Finally, looking at the nRF52833 RTC registers I could not find a way of setting the time. Is there one?

    None of the RTC's peripheral on embedded devices I know tells you time but tell you number of ticks. The frequency of tick increment depends on your configuration on PRESCALER: For actual time you either need to rely on the higher level libraries or utilities from the RTOS.

    My question was about setting the RTC time (ticks) not reading it. I could not find a register that would allow such operation. 

    But I assumed that your main issue is to keep track of time between reboots. That is the trickiest part and that is where you need to access persistent storage. 

    Yes, this ticket, as the title suggests, is about keeping time between reboots. 

    You cannot restore old value into RTC register but you need to have your own application memory (static variable) or similar to remember the old offsets of time before reboot.

    I will probably have to store the old value in flash and read it back after reboot...

    Also, what does the first line in red mean?

    This information applies to the following SoftDevices: S130, S132, S332

    I do not know which SoftDevice I am using. How do I find out?

    Kind regards

    Mohamed

  • Not quite what you are looking for, but there is a way which seems to work fairly reliably; however note the only reliable solution is to use an external battery-backed RTC unless you can find a way to use the 2 x 8-bit GPREGRET registers, the latter by perhaps storing number of seconds since last flash write of full time field (note some bootloaders use GPREGRET registers for bootup modes so they may not be available).

    The trick which I use is to note that internal RAM is never reset, though it may be "corrupted". Provided one or more RAM areas are not selected for power down during Off, one or more instances of the tick can be held and used to continue operation after a reset. Memory corruption is detected by loading a unique value into the same RAM area. Time of startup after a reset is lost but that time may be measured (manual calibration step) and used as compensation after the reset provided the RTC is always restarted before any other time-consuming action. The example here ticks at 8 times per second, but typically once per second might be more appropriate. Note this method will not of course work across an extended power removal such as when a battery is removed.

    // Place following data in section .noinit so it doesn't get wiped on a reset
    #pragma default_variable_attributes = @ ".noinit"
      static volatile uint32_t mIamInitializedRTC; // Valid data indication for this data
      // Packet Sample Time timer interrupt, typically 8 times per second
      static volatile uint32_t mPacketSampleTimer;
      // 32-bit unsigned RTC time: number of 125 millisecond ticks from Jan 1st 2024
      static volatile uint32_t mPacketSampleTimer;
    #pragma default_variable_attributes =
    // End - Place following data in section .noinit so it doesn't get wiped on a reset
    
    bool CheckPacketSampleTimeValid(void)
    {
        // See if RTC data is valid - Use unique device ID as the valid signature
        return (mIamInitializedRTC == NRF_FICR->DEVICEID[0]);
    }
    
    void InitializeRTC(void)
    {
        // See if RTC data is valid - Use unique device ID as the valid signature
        if (!CheckPacketSampleTimeValid())
        {
           // RTC backup failed, clear the stored time
           mPacketSampleTimer = 0;
           // Indicated data is now valid - Use unique device ID as the valid signature
           mIamInitializedRTC = NRF_FICR->DEVICEID[0];
        }
        // Configure RTC and add in known reset startup time
        start lfclk and rtc
    }
    .

  • Hi qwertynoon,

    Apologies for not responding to your question earlier. It got lost in the long trail of messages and missed it. Thank you for your suggestion. However, I think use of the UICR works only if you are writing to that location once and then read back from it. If, like in my use case, I need to store the time a multitude number of times then UICR is not a good option.

    Kind regards

    Mohamed

  • Hello hmolesworth,

    I tried a similar approach but it does not seem to work.

    First, I could not use exactly your syntax #pragma default_variable_attributes = @ ".noinit".
    My compiler did not recognise the pragma default_variable_attributes, probably because I am using an old version of the tools NCS v1.7.0. So, I used this instead,

    #define NOINIT_SECTION ".noinit.pid_timer"

    volatile uint32_t g_timer_dev_life __attribute__((section(NOINIT_SECTION)));

    g_timer_dev_life is the variable I am using to store the data I would like to keep across reboots.

    However, my variable is getting re-initialised to 0 after every reboot.

    Any reason why it is not working?

    Kind regards

    Mohamed

  • Maybe try this, gcc usually has a pre-defined ".non_init" section - check the map file to verify:

    volatile uint32_t g_timer_dev_life __attribute__((section(".non_init")));

    Note if using a Bootloader must ensure that doesn't scribble over everything as well ..

Reply Children
Related