Maximum sleep time nRF52840

Hallo,

currently I'm testing sleep variants for nRF52840. I'm using nRF52840-DK and Zephyr build v2.7.99-ncs1-1.

By means of the RTC timer one can handle sleeping quite comfortable:

z_nrf_rtc_timer_set((int32_t)rtc_chan, rtc_ticks, rtc_expiry_handler, NULL);

k_sleep(K_FOREVER);

will set the timer and after that line one can sleep forever. An expiring timer (after rtc_ticks) will call the rtc_expiry_handler function, where a wake-up of the main thread can be done.The value for rtc_ticks is calculated by means of:

rtc_ticks = z_nrf_rtc_timer_get_ticks(t);

"t" in the end is an uint32_t type.

My test implementation runs well in a small test app for sleep times up to 512 seconds. For longer times z_nrf_rtc_timer_get_ticks(..) comes up with error -22. First I thought that there is an issue of register length, since in z_nrf_rtc_timer_get_ticks(..) there is a COUNTER_SPAN, which is defined as

#define COUNTER_BIT_WIDTH 24U
#define COUNTER_SPAN BIT(COUNTER_BIT_WIDTH)

But I realised that for the 512 second case the number of ticks is 16851770, which is already more than a 24-bit-value. In general, much higher tick values should be possible - the return value of z_nrf_rtc_timer_get_ticks(..) is an uint64_t.

Therefore the question: What should I do to extend the sleep time of (much) more than 512 seconds?

  • Hello,

    The easiest would be simply to use the k_sleep() with the number of seconds you want to sleep. When you want to sleep for the amount of time you do here, the biggest contributor to the inaccuracy will be the tolerance of the lfclk (not the execution time between calling k_sleep()).

    But to answer your question, you can change the prescaler of the rtc you are using if you want more than 512seconds:
    https://infocenter.nordicsemi.com/topic/ps_nrf52840/rtc.html#concept_iwc_1mj_sr 

    Kenneth

  • Hallo Kenneth,

    sorry for answering that late - I fixed a lot of other issues in the meantime, when short times for testing were perfect. Furthermore, I updated to Zephyr 3.2.99 and ncs2.2. Now I'm back at the question of sleep times > 512 seconds with nRF52840.

    I allocate an rtc timer channel by means of z_nrf_rtc_timer_chan_alloc(). Than I set the time I need with z_nrf_rtc_timer_set((int32_t)rtc_chan, rtc_ticks, rtc_expiry_handler, NULL), which also starts the timer. The rtc_expiry_handler - called after rtc_ticks is over - includes stopping the timer and wake-up of my main thread.

    This setting runs well for all time periods up to 512 seconds.

    For setting the prescaler, I used nrf_rtc_prescaler_set(RTC, x) with x representing the prescaler. This didn't work neighter for #define RTC NRF_RTC0 nor for #define RTC NRF_RTC1, but the logical connection between my rtc channel and RTC0/1 is anyway not clear to me.

    Up to now I coudn't find another way to set a prescaler value, especially by means of the rtc channel I have. Also I coudn't find an example of a different RTC usage, which I can compile and run (including the example given in github.com/.../main.c, which is also more than 4 years old).

    Do you have any helpful idea?

    Best regards
    Axel

  • Hello,

    Some of the peripherals are used by zephyr OS and MPSL, ref:
    https://developer.nordicsemi.com/nRF_Connect_SDK/doc/latest/nrfxlib/mpsl/doc/mpsl.html 
    https://developer.nordicsemi.com/nRF_Connect_SDK/doc/latest/nrfxlib/softdevice_controller/doc/softdevice_controller.html#integration-with-applications 

    For instanc I expect configuring RTC0 will not work since it's used already, though I expect you should be able to access some of the other RTC's, though to configure PRESCALER make sure you do that before you start RTCx in question.

    Kenneth

  • Hallo Kenneth,

    shortly the intermediate result so far:

    - I still can't find a function to set a prescaler value directly from a main function running at nRF.

    - I can modify in /nrfx/hal/nrf_rtc.h the function nrf_rtc_cc_set(..) by adding a simple prescaler setting, e.g.:

      p_reg->PRESCALER = (uint32_t)1;

      But it is not my intension to modify the nRF or Zephyr sources.

    - With the modification, I can double short periods (longer values I didn't test so far, but I assume the doubling will work). But in that case I also modify the uptime counter, which runs slower too - the reported time stays the same, even if the sleep time effectively doubles. The reason for that is in my current opinion that in /drivers/timer/nrf_rtc_timer.c there is a fixed definition: #define RTC NRF_RTC1 (line 21), which means there is no chance to change the RTC used maybe to NRF_RTC2.

    So I'm still looking for a feasible solution.

    Kind regards

    Axel

  • Maybe you are spending much time on something that can be solved different ways, for instanc if you want to run something every 1000seconds, you can just set a 500second timeout, and have a counter in the 500second timeout handler to know that you need to run something every second time.

    Doing this way will have no impact on the sleep current, e.g. assume wakeup of 50us every 500second for 5mA = ~0.5nA.

    Kenneth

Related