Clarifications on errata "[20] RTC: Register values are invalid"

This is the errata:

Symptoms

RTC registers will not contain the correct/expected value if read.

Conditions

The RTC has been idle.

Consequences

RTC configuration cannot be determined by reading RTC registers.

Workaround

Execute the below code before you use RTC.
NRF_CLOCK->EVENTS_LFCLKSTARTED = 0;
NRF_CLOCK->TASKS_LFCLKSTART = 1;
while (NRF_CLOCK->EVENTS_LFCLKSTARTED == 0) {}
NRF_RTC0->TASKS_STOP = 0;

My questions:

  1. Idle for how long time? Idle after it has been used before or does it also have to be done after every mcu reset, i.e. before the first time the RTC is used after boot?
  2. Do I have to re-do this every time after I have stopped the LFCLK? Or after every time I have stopped the RTC when I want to start it again?
  3. Can an arbitrary amount of time pass between line 3 and 4?
  4. Can line 4 (TASKS_STOP) be reordered, i.e. be executed before the LFCLK is started instead, or while it is being started (e.g. if using LFXO as source, it is ok to run line 4 once LFCLKSTAT says running, e.g. before SRC has switched from RC to LFXO)?
  5. What "configuration" registers are affected? The only configuration register I see present on the RTC peripheral is the PRESCALER. Does this mean as long as I only write to this register and never read from it, I can ignore this errata?
  6. Is it a typo that 0 should be written to TASKS_STOP? According to the PS only 1 is a valid value to write to the TASKS_STOP register.
  7. Any code that can reproduce the issue? I cannot reproduce the issue no matter what I've tried so far.
Parents
  • Hi Emil,

    You need apply this workaround everytime you boot/reboot or whenever you have forced the LFCLK to stop and start again. That means that as long as the LF-clock is running, the power domains in which the RTCs  reside is never switched off and the reads will return correct results.

    Can an arbitrary amount of time pass between line 3 and 4?

    Depends on the clock used, this time should be fixed per chip/clock configuration. It can vary from one chip to the other in a cycle or two difference.

    Can line 4 (TASKS_STOP) be reordered, i.e. be executed before the LFCLK is started instead, or while it is being started (e.g. if using LFXO as source, it is ok to run line 4 once LFCLKSTAT says running, e.g. before SRC has switched from RC to LFXO)?

    We do not know, the workaround we provided have been tested. Reordering is not recommended or suggested.

    What "configuration" registers are affected? The only configuration register I see present on the RTC peripheral is the PRESCALER. Does this mean as long as I only write to this register and never read from it, I can ignore this errata?

    Does not matter, we should assume all registers are effected. 

    Is it a typo that 0 should be written to TASKS_STOP? According to the PS only 1 is a valid value to write to the TASKS_STOP register.

    We need to have a dummy access to the RTC and writing 0 to that register does nothing but accesses the module clearly poking power management of the device to tell it to activate the resources needed by RTC.

    Any code that can reproduce the issue? I cannot reproduce the issue no matter what I've tried so far.

    Might be that this is very timing related effecting some chips and not all. Best is to not take the risk and apply this workraound at the system startup. 

  • Thanks for the extremely fast and detailed response!

    Can an arbitrary amount of time pass between line 3 and 4?

    Depends on the clock used, this time should be fixed per chip/clock configuration. It can vary from one chip to the other in a cycle or two difference.

    What I really meant here was, are we allowed to do other things between these lines so that the NRF_RTC0->TASKS_STOP = 0; is executed some time later? Otherwise applying the same workaround for both RTC0 and RTC1 would be impossible (since that would require a re-start of LFCLK if we literally copy-paste the code twice for both RTC0 and RTC1). I guess if we want to use RTC1 as well the correct thing is to simply append NRF_RTC1->TASKS_STOP = 0; at the end.

    Some follow-up questions:

    1. The busy-loop maxes the CPU. Will the workaround work as well if we set up an interrupt for LFCLKSTARTED and wait for that interrupt to be triggered instead, putting the CPU to sleep in the meantime? That will result in that the TASKS_STOP = 0; line will be executed a few microseconds later, since it takes some time for the CPU to wake up.

    2. Is this workaround already implemented in nRF Connect SDK / nrfx / nRF5 SDK? I tried to do a fulltext seach on "TASKS_STOP = 0" but didn't find anything relevant. I also tried looking in https://github.com/NordicSemiconductor/nrfx/blob/master/haly/nrfy_rtc.h as well as the older app_timer.c in nRF5 SDK but didn't find anything there either. Since the errata text is really vague on why/how the workaround code works or what the key instructions are making it work, it's difficult to know if the workaround can be fulfilled in some other way apart from the exact instruction sequence supplied.

    From your description "We need to have a dummy access to the RTC and writing 0 to that register does nothing but accesses the module clearly poking power management of the device to tell it to activate the resources needed by RTC." it seems the key here in the workaround is to write anything to the RTC while LFCLK is running to "poke" the power management to activate the resources needed by RTC. Otherwise reading some register can return garbage since the RTC at that point does not have the resources needed enabled.

  • Emil Lenngren said:
    What I really meant here was, are we allowed to do other things between these lines so that the NRF_RTC0->TASKS_STOP = 0; is executed some time later?
    Emil Lenngren said:
    I guess if we want to use RTC1 as well the correct thing is to simply append NRF_RTC1->TASKS_STOP = 0; at the end

    Correct.

    Right after the LFCLK is started you can just have a dummy read in both the RTCs like below, we just need a dummy read on that register and some traffic on the transport bus with RTC peripheral being the target.

    NRF_CLOCK->EVENTS_LFCLKSTARTED = 0;
    NRF_CLOCK->TASKS_LFCLKSTART = 1;
    while (NRF_CLOCK->EVENTS_LFCLKSTARTED == 0) {}
    NRF_RTC0->TASKS_STOP = 0;
    NRF_RTC1->TASKS_STOP = 0;

    The above mean that you have applied the workaround for both instances of RTC at startup.

    And yes you can have a delay between the LFCLK started and the fourth line, but it might be risky if some other context (with higher interrupt priority) stole the CPU and the new context started using RTC without the workaround being complete. This is less likely scenario, but a possibility that cannot be ignored in firmware design.

    Emil Lenngren said:
    . The busy-loop maxes the CPU. Will the workaround work as well if we set up an interrupt for LFCLKSTARTED and wait for that interrupt to be triggered instead, putting the CPU to sleep in the meantime? That will result in that the TASKS_STOP = 0; line will be executed a few microseconds later, since it takes some time for the CPU to wake up.

    This will work aswell as long as you make sure that from the time the RTC interrupt is triggered in hardware to the time RTC ISR is called, the CPU will not execute any other higher priority context where it will either 

    1. do something that in turns disable the LFCLK or
    2. try to use the RTC without the workaround is not completed.
    Emil Lenngren said:
    2. Is this workaround already implemented in nRF Connect SDK / nrfx / nRF5 SDK? I tried to do a fulltext seach on "TASKS_STOP = 0" but didn't find anything relevant. I also tried looking

    This is excellent question, you are right. The SDK does not seem to be applying this workaround both in nRF5SDK and in nrF Connect SDK. I think that the condition where RTC is idle is never reached the way rtc drivers and libraries are written. That means that the drivers and libraries make sure that from the time RTC is initialized, there is no instance where it gets to IDLE state.

  • Thanks for the quick reply. It makes most things clear now.

    However,

    I think that the condition where RTC is idle is never reached the way rtc drivers and libraries are written. That means that the drivers and libraries make sure that from the time RTC is initialized, there is no instance where it gets to IDLE state.

    From the above, it seems like "idle" means any time after RTC has been used until the next time RTC is used.

    Doesn't that contradict your reply for my initial first question?

    You need apply this workaround everytime you boot/reboot

    That seems to imply that "idle" could also refer to the time between boot and we use the RTC the first time?

Reply
  • Thanks for the quick reply. It makes most things clear now.

    However,

    I think that the condition where RTC is idle is never reached the way rtc drivers and libraries are written. That means that the drivers and libraries make sure that from the time RTC is initialized, there is no instance where it gets to IDLE state.

    From the above, it seems like "idle" means any time after RTC has been used until the next time RTC is used.

    Doesn't that contradict your reply for my initial first question?

    You need apply this workaround everytime you boot/reboot

    That seems to imply that "idle" could also refer to the time between boot and we use the RTC the first time?

Children
  • Emil Lenngren said:

    From the above, it seems like "idle" means any time after RTC has been used until the next time RTC is used.

    Doesn't that contradict your reply for my initial first question?

    RTC idle means that the power regulator to it and the LFCLK most likely have been turned off. In the SDK and the protocol stacks, it looks like once the RTC is initialized, it is never allowed to go into idle states where the hardware power management will at any state decide to turn off power and clock to it as the part of automatic power management of a peripheral. This automatic power management to my understanding may happens when you have TASKS_STOP on RTC after it has been started and being used for a while.

    This said, the SDK libraries and drivers does not seem to have applied this workaround and I am not sure why. I need to ask this to the hardware engineers and the SDK team. 

  • I need to ask this to the hardware engineers and the SDK team. 

    Hi. Did you receive any reply yet?

Related