Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Kernel high-resolution timer support #6498

Open
carlescufi opened this issue Mar 7, 2018 · 20 comments
Open

Kernel high-resolution timer support #6498

carlescufi opened this issue Mar 7, 2018 · 20 comments

Comments

@carlescufi
Copy link
Member

@carlescufi carlescufi commented Mar 7, 2018

Several users in the mailing list have asked for highly precise busy-wait primitives that allow them to time with precision.

I don't know what sort of APIs we'd need, but at the very least something like:

k_hr_busy_wait(u64_t microseconds)

@carlescufi
Copy link
Member Author

@carlescufi carlescufi commented Mar 7, 2018

@carlescufi carlescufi changed the title Kernel high-resoution timers Kernel high-resolution timer support Mar 7, 2018
@SebastianBoe
Copy link
Contributor

@SebastianBoe SebastianBoe commented Mar 7, 2018

In addition to a high-resolution timer API, I imagine users that have the high-frequency clock always-on anyway would like to be able to Kconfigure "_arch_k_cycle_get_32" to use the high-frequency clock instead of the low-frequency clock.

@diytronic
Copy link
Contributor

@diytronic diytronic commented Mar 7, 2018

Why only a microseconds resolution?
May be use same approach as system clock - using timer ticks?
Something like k_hr_cycle_get

@carlescufi
Copy link
Member Author

@carlescufi carlescufi commented Mar 7, 2018

@diytronic

Why only a microseconds resolution?

Agreed, I checked the Linux HR timer API and it uses nanoseconds.

May be use same approach as system clock - using timer ticks?

Well, there is also k_busy_wait(u32_t microseconds) now already in the kernel

@carlescufi
Copy link
Member Author

@carlescufi carlescufi commented Mar 7, 2018

@SebastianBoe

In addition to a high-resolution timer API, I imagine users that have the high-frequency clock always-on anyway would like to be able to Kconfigure "_arch_k_cycle_get_32" to use the high-frequency clock instead of the low-frequency clock.

Agreed, the only issue in the Nordic platforms then is that we'd need a secondary implementation of our system timer driver that uses a timer instead of the RTC.

@andyross
Copy link
Contributor

@andyross andyross commented Mar 7, 2018

Yeah, on systems with a high precision cycle counter, k_busy_wait() does what you want already. It just spins on k_cycle_get_32() as described. On essentially all the current platforms, k_cycle_get_32() is provided out of the timer driver as _timer_cycle_get_32().

Pretty sure you have what you want already, no?

@carlescufi
Copy link
Member Author

@carlescufi carlescufi commented Mar 8, 2018

@andyross yeah, I think so. Unless we really need nanosecond precision, but on current microcontrollers this make little sense actually, since the overhead in instructions would already clobber the added resolution.

@diytronic would that cover your needs, if k_busy_wait() was actually precise on Nordic platforms?

@diytronic
Copy link
Contributor

@diytronic diytronic commented Mar 8, 2018

@carlescufi For current task yes, but I am implementing 1-wire bus now (need it for ds18b20 sensor, so really writing driver for it too) and among the standard mode 1-wire has so called overdrive mode (faster). Here you can look at timings (just to make sure it is not my stupid caprice) https://www.maximintegrated.com/en/app-notes/index.mvp/id/126 So in overdrive mode it required for example 1us, 2.5us delays and so on. So on my opinion nanosecond resolution could be way better.

@diytronic
Copy link
Contributor

@diytronic diytronic commented Mar 8, 2018

@carlescufi BTW just checked for example CAN BUS timings https://www.nxp.com/docs/en/application-note/AN1798.pdf So nanosecond delays there. So I think nanosecond delay must be implemented.

@andyross
Copy link
Contributor

@andyross andyross commented Mar 10, 2018

So... two issues: one is that k_busy_wait() only allows a microsecond argument, where the actual cycle counter it wraps can (usually) do better. I don't see any reason we can't have a k_nano_wait() or whatever that takes different units, though honestly an app with precision requirements like this could trivially write its own loop over k_cycle_get_32().

But a request for true nanosecond precision just isn't going to work on CPUs running clocks 10-100x slower than that. We can't fix that.

@diytronic
Copy link
Contributor

@diytronic diytronic commented Mar 10, 2018

@andyross

honestly an app with precision requirements like this could trivially write its own loop over k_cycle_get_32().

No - it does not work. For example for nRF51x MCU family system tick used 32kHz timer which is unable to provide even microseconds resolution. Really this was the only reason for k_busy_wait API call implementation discussion.

@diytronic
Copy link
Contributor

@diytronic diytronic commented Mar 10, 2018

@andyross

But a request for true nanosecond precision just isn't going to work on CPUs running clocks 10-100x slower than that. We can't fix that.

nRF51x MCU has separate 16Mhz timer which can be used for this. So I expect some other MCU can have something similar. Mean some built in mechanisms not related to system clock.

@andyross
Copy link
Contributor

@andyross andyross commented Mar 16, 2018

@diytronic: k_cycle_get_32() returns a hardware cycle counter, not scheduler ticks (except on platforms that have no such timer, I guess). I'm all but certain this would work just fine on nRF1x. Are you sure you actually have a problem with the API as it stands (which has some precision aliasing due to microsecond conversion, but otherwise should be close to cycle accurate)?

@diytronic
Copy link
Contributor

@diytronic diytronic commented Mar 16, 2018

@andyross I am absolutely sure, because I tried to get a delay based on this http://docs.zephyrproject.org/kernel/timing/clocks.html#measuring-time-with-high-precision and finally got that k_cycle_get_32() working with 32kHz frequency what was a big surprise (tested on nRF51822 MCU). So I discovered code and found what 32kHz timer used for that (nRF51822 has second timer working at 16Mhz). So I asked in mailing list about it and got the following reply

The reason for such a low-resolution system clock is power consumption. Running on the 32KHz clock is much more power efficient than requiring the 16MHz clock continuously

And later this

The CPU itself still works at 16MHz even when the 16MHz external crystal is not enabled, this does not impact actual processing power performance. The idea is that the 16MHz external crystal is only required under certain conditions (Bluetooth Low Energy radio intervals for example) but can be kept off the rest of the time.

But anyway checking k_cycle_get_32() (pin output with logic analyser) I see 32kHz frequency of k_cycle_get_32(). So to get smaller delay I am separately turning on and using 16Mhz timer.

@mekkaoui
Copy link

@mekkaoui mekkaoui commented May 14, 2018

I need a 1us timestamp "service". In my use-case it is simply a variable that increments every 1 us infinitely, and that gets read asynchronously as per need.

-be always monotonic at a 1us resolution
-Take care of any rollovers (64bit variable would take care of this almost at any micro-controller clock)
-If it uses interrupts, it does it right to avoid race condition

Neglecting any os issues, would not this be easy to do in the nrf devices by using a 32b-wide timer clocked at a 1MHz and a compare register to detect rollovers. The timer
would generate an interrupt every hour or so to indicate a rollover event.

Thanks

Abderrezak

@andyross
Copy link
Contributor

@andyross andyross commented May 14, 2018

Saw this came up again on the mailing list. As diytronic explains above: NRF51 devices have power consumption requirements that mean that the system clock will simply never be able to produce timing information of this precision in a way that Zephyr can expose as a straightforward API. If the clock has to be kHZ-scale at idle, there's just no way to get the main timer (i.e. k_cycle_get_32(), and its derivatives like k_busy_wait()) to give you answers in microseconds. You have to use some other device, and manage it outside the system timer framework.

I don't think that would be a bad API to have available, but it's much more complicated than "high-resolution timer support", which we already have.

@carlescufi
Copy link
Member Author

@carlescufi carlescufi commented Dec 11, 2018

Copying @pizi-nordic since this was raised in the API meeting today by him.

@nickyameen
Copy link

@nickyameen nickyameen commented Jan 14, 2019

I am working an IO-Link application using the FRDM-K64F development board. This application requires the use of timers in microseconds. There are multiple timers that need to be implemented in microseconds.

As of now k_timer_start() passes in a time duration and period in milliseconds.

@carlescufi
Copy link
Member Author

@carlescufi carlescufi commented Feb 5, 2019

Setting the priority high due to popular demand for this feature

@cfriedt
Copy link
Collaborator

@cfriedt cfriedt commented May 23, 2020

Would be useful to have hr timers for a nanosleep(2) call (#25559). I have not looked into Zephyr's clock structure yet though.

It would be nice to register multiple clock sources and make them available to applications / userspace similar to how clock_getres, clock_gettime, etc work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
10 participants