NRF52 and timing - actual state and what functions to use? #nrf52-pca10040


Martin Kozusky
 

Hi,
I understand that there are some problems because of 32768Hz RTC with NRF52832 as referenced here: https://github.com/zephyrproject-rtos/zephyr/issues/9904  , there are some already merged PRs (like https://github.com/zephyrproject-rtos/zephyr/pull/16782 )  and some waiting to merge, so what is the actual state at 2.1.0?

I want to ask:

 1 - what is the best solution to call my function every 1ms (or will it be 1.007ms?), is it ok just to use k_timer? Is "next expiration time" calculated just by adding period to current time (that would make a big time diff after many calls)  or does it use k_uptime_get*number of expirations to calculate next expiration time?

 2 -  what is the best solution for most precise long-term time keeping?  Let's say i don't want more that 1 minute diff in 20 days. Can I just use k_uptime_get? I would like to make my HW design without aditional external RTC, which can be almost as expensive as another NRF52832 - is it even possible somehow? Or do you have any tip for some cheap low-power RTC?

 3 - would using external 16MHz/32MHz (or another frequency) oscilator solve anything?

 4 - as someone already wrote here: https://lists.zephyrproject.org/g/users/topic/28021125  would it be possible to use timer peripheral (with external osc.) to generate better timing (as I would normaly do with bare-metal sources)?


Thanks.


Martin Kozusky
 

Hi,
I understand that there are some problems because of 32768Hz RTC (I am now using NRF52-DK and want to use NRF52832 in my new HW) as referenced here: https://github.com/zephyrproject-rtos/zephyr/issues/9904   there are some already merged PRs (like https://github.com/zephyrproject-rtos/zephyr/pull/16782 )  and some waiting to merge.

I want to ask:

 1 - what is the best solution to call my function every 1ms (or will it be 1.007ms?), is it ok just to use k_timer? Is "next expiration time" calculated just by adding period to current time (that would make a big time diff after many calls)  or does it use k_uptime_get*number of expirations to calculate next expiration time?

 2 -  what is the best solution for most precise long-term time keeping?  Let's say i don't want more that 1 minute diff in 20 days. Can I just use k_uptime_get? I would like to make my HW design without aditional external RTC, which can be almost as expensive as another NRF52832 - is it even possible somehow? Or do you have any tip for some cheap low-power RTC?

 3 - would using external 16MHz/32MHz (or another frequency) oscilator solve anything?

 4 - as someone already wrote here: https://lists.zephyrproject.org/g/users/topic/28021125  would it be possible to use timer peripheral (with external osc.) to generate better timing (as I would normaly do on bare-metal)?


Thanks.


Andy Ross
 

On 1/5/20 4:30 AM, Martin Kozusky [newsgroups] wrote:
1 - what is the best solution to call my function every 1ms (or will
it be 1.007ms?), is it ok just to use k_timer? Is "next expiration
time" calculated just by adding period to current time (that would
make a big time diff after many calls) or does it use
k_uptime_get*number of expirations to calculate next expiration
time?
Periodic k_timer's do not work in fractional ticks, no. If you
schedule a 1000ms timeout it will be rounded up internally to exactly
33 hardware cycles, and that process will repeat each cycle. So you
would see the ~993 Hz tick rate you calculated. If you want to work
in fractional ticks, the application needs to do that math itself.

2 - what is the best solution for most precise long-term time
keeping? Let's say i don't want more that 1 minute diff in 20
days. Can I just use k_uptime_get?
Long term time is kept as a 64 bit count of ticks, so it's not subject
to the kind of round-off errors that periodic timers are. As long as
your app isn't dropping or delaying the counter interrupts, the uptime
value should be as accurate as your crystal is.

If you want to get 1 callback per second as a long term average, you
can (with care) compute your timeout as an offset from system start or
some other time reference instead of "now" (i.e. the Nth timeout will
happen at "N * 1000ms", plus a little precision slop due to the clock
mismatch). There's actually an API change which will make this kind
of code significantly easier, see
https://github.com/zephyrproject-rtos/zephyr/issues/21305

As far as using a different oscillator to drive the timer, that's
possible but requires some driver fiddling. I'll let the Nordic folks
speak to that. One option might be to use the generic ARM SysTick
driver, which doesn't have the rate mismatch issues of the 32kHz
timer, but doesn't have the low power idle characteristics.

Andy


Martin Kozusky
 

Dne 06.01.2020 v 18:31 Andy Ross napsal(a):
On 1/5/20 4:30 AM, Martin Kozusky [newsgroups] wrote:
1 - what is the best solution to call my function every 1ms (or will
it be 1.007ms?), is it ok just to use k_timer? Is "next expiration
time" calculated just by adding period to current time (that would
make a big time diff after many calls) or does it use
k_uptime_get*number of expirations to calculate next expiration
time?
Periodic k_timer's do not work in fractional ticks, no. If you
schedule a 1000ms timeout it will be rounded up internally to exactly
33 hardware cycles, and that process will repeat each cycle.  So you
would see the ~993 Hz tick rate you calculated.  If you want to work
in fractional ticks, the application needs to do that math itself.
is it 1000ms timeout = 33 cycles, or 1ms timeout = 33 cycles? This is acceptable for short-term timeouts.

2 - what is the best solution for most precise long-term time
keeping?  Let's say i don't want more that 1 minute diff in 20
days. Can I just use k_uptime_get?
Long term time is kept as a 64 bit count of ticks, so it's not subject
to the kind of round-off errors that periodic timers are.  As long as
your app isn't dropping or delaying the counter interrupts, the uptime
value should be as accurate as your crystal is.

If you want to get 1 callback per second as a long term average, you
can (with care) compute your timeout as an offset from system start or
some other time reference instead of "now" (i.e. the Nth timeout will
happen at "N * 1000ms", plus a little precision slop due to the clock
mismatch).  There's actually an API change which will make this kind
of code significantly easier, see
https://github.com/zephyrproject-rtos/zephyr/issues/21305
When this gets into 2.2, can I use "k_uptime_ticks() / 32768" to get the exact time in seconds?

As far as using a different oscillator to drive the timer, that's
possible but requires some driver fiddling.  I'll let the Nordic folks
speak to that.  One option might be to use the generic ARM SysTick
driver, which doesn't have the rate mismatch issues of the 32kHz
timer, but doesn't have the low power idle characteristics.
On another project, I would like to be sleeping most of the time to save power and want to be woken by pin interrupt or 1 sec timeout, so it is good idea to have clock in low-power.

BTW: When I enter to sleep by k_sleep(), is there  any change in power consumption besides thread being put to sleep? Or do I have to call device_set_power_state(DEVICE_PM_LOW_POWER_STATE) to enter low-power mode? Will I be automaticaly put to DEVICE_PM_ACTIVE_STATE when there is an pin interrupt and is there any way how to get number of ticks I've been in low-power mode since I was woken by pin interrupt? (are ticks also incremented in low-power mode?) (on bare-metal I would set RTC modulo to wake after 1 second, go to low-power and if I got woken earlier by pin interrupt, I would read RTC counter to get the exact time I was sleeping or if I got woken by RTC INT, I would know it was exactly 1 sec, then do some stuff, again setup RTC, go to sleep  ... is this even possible with Zephyr and NRF52832? )

Andy
Thanks,
Martin


Chruściński, Krzysztof
 

Hi Martin,

Nrf52832 has 3 RTC's. RTC0 is used for Bluetooth, RTC1 for system clock and RTC2 is usually available for application. You can use RTC2 with counter driver API (see counter.h). Then you can schedule absolute alarms at tick precision.

Regards,
Krzysztof

-----Original Message-----
From: users@lists.zephyrproject.org <users@lists.zephyrproject.org> On Behalf Of Martin Kozusky [newsgroups] via Lists.Zephyrproject.Org
Sent: Sunday, January 5, 2020 9:59 AM
To: users@lists.zephyrproject.org
Cc: users@lists.zephyrproject.org
Subject: [Zephyr-users] NRF52 and timing - actual state and what functions to use?

Hi,
I understand that there are some problems because of 32768Hz RTC (I am now using NRF52-DK and want to use NRF52832 in my new HW) as referenced
here: https://github.com/zephyrproject-rtos/zephyr/issues/9904   there are some already merged PRs (like
https://github.com/zephyrproject-rtos/zephyr/pull/16782 )  and some waiting to merge.

I want to ask:

 1 - what is the best solution to call my function every 1ms (or will it be 1.007ms?), is it ok just to use k_timer? Is "next expiration time"
calculated just by adding period to current time (that would make a big time diff after many calls)  or does it use k_uptime_get*number of expirations to calculate next expiration time?

 2 -  what is the best solution for most precise long-term time keeping?  Let's say i don't want more that 1 minute diff in 20 days. Can I just use k_uptime_get? I would like to make my HW design without aditional external RTC, which can be almost as expensive as another
NRF52832 - is it even possible somehow? Or do you have any tip for some cheap low-power RTC?

 3 - would using external 16MHz/32MHz (or another frequency) oscilator solve anything?

 4 - as someone already wrote here:
https://lists.zephyrproject.org/g/users/topic/28021125  would it be possible to use timer peripheral (with external osc.) to generate better timing (as I would normaly do on bare-metal)?


Thanks.