-
Notifications
You must be signed in to change notification settings - Fork 3k
[HAL] Add support for 64 bit us timestamp #4094
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
Conversation
@@ -46,32 +46,39 @@ void Timer::stop() { | |||
|
|||
int Timer::read_us() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you think we can get away with updating this return type?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's an excellent question. I don't have the answer, I choose a conservative approach for this PR even if it hurts to see this return type be int.
drivers/Timer.cpp
Outdated
us_timestamp_t time = _time + slicetime(); | ||
core_util_critical_section_exit(); | ||
time = time / 1000; | ||
return (float)read_ms() / 1000.0f; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like time
does not get used. Also is this able to return us
precision? or is that out of the range of 32-bit floats?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@pan- : time not used?
drivers/Timer.cpp
Outdated
} | ||
|
||
int Timer::read_ms() { | ||
return read_us() / 1000; | ||
core_util_critical_section_enter(); | ||
us_timestamp_t time = _time + slicetime(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
tangent: The expression _time + slicetime()
is repeated quite a bit. Should we actually be adding _time
in the slicetime function?
@@ -44,6 +44,10 @@ void TimerEvent::insert(timestamp_t timestamp) { | |||
ticker_insert_event(_ticker_data, &event, timestamp, (uint32_t)this); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is TimerEvent::insert
used at all now?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is a public interface, so it might be used by user code.
hal/mbed_ticker_api.c
Outdated
#include <stddef.h> | ||
#include "hal/ticker_api.h" | ||
#include "platform/mbed_critical.h" | ||
|
||
void ticker_set_handler(const ticker_data_t *const data, ticker_event_handler handler) { | ||
data->interface->init(); | ||
#define MBED_MIN(x,y) (((x)<(y))?(x):(y)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thought: Should this be static inline to avoid side-effects becoming duplicated?
This is looking great 👍, Left some review comments. Another thought (perhaps this should be a separate pr), some devices (NCS36510 for example) only provide a 16-bit timer. Do you think this could be extended to support timers with any bit-width? |
@geky Yes it would be really easy to support timer with any bit width if the interface provide this information. To support a 16 bit timer with the current code. The interface just have to keep state of its counter as a 32 bit counter. The interface can trigger interrupt whenever it wants (at every overflow for instance) without tracking the time requested because the ticker code supports spurious interrupts. |
Just tried this pr with a 16-bit timer and it worked perfectly! This is a great update to the api. Here's what the NCS36510 16b timer code looks like after this pr: geky@492b558 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1 for the tests, extensive, have to have another look at them :-)
Just general comments.
hal/mbed_ticker_api.c
Outdated
* | ||
* It is important to note that the result will **never** be in the past. If the | ||
* value of the low res timetamp is less than the low res part of the reference | ||
* timestamp then an overflow is |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
then this is overflow or how a user should read this (looks like unfinished sentence).
hal/mbed_ticker_api.c
Outdated
* @param ref: The timestamp of reference. | ||
* @param relative_timestamp: The timestamp to convert. | ||
*/ | ||
static us_timestamp_t convert_relative_timestamp(us_timestamp_t ref, timestamp_t relative_timestamp) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
style: fix the body {
(newline) in some functions in this file (at least new functions, we should fix this file later). plus bool is misaligned below?
drivers/Timer.cpp
Outdated
us_timestamp_t time = _time + slicetime(); | ||
core_util_critical_section_exit(); | ||
time = time / 1000; | ||
return (float)read_ms() / 1000.0f; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@pan- : time not used?
hal/ticker_api.h
Outdated
* @note prefer the use of ticker_insert_event_us which allows registration of | ||
* absolute timestamp. | ||
* | ||
* @param data The ticker's data |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
data = ticker, plus update the description
hal/ticker_api.h
Outdated
* | ||
* @param data The ticker's data | ||
* @param obj The event object to be inserted to the queue | ||
* @param timestamp The event's timestamp |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
relative timestamp in this case
|
||
/* Go through all the pending TimerEvents */ | ||
while (1) { | ||
if (data->queue->head == NULL) { | ||
// There are no more TimerEvents left, so disable matches. | ||
data->interface->disable_interrupt(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
are we disabling interrupts anywhere? there are 3 removals for disable_interrupt() call. Is this function becoming redundant ? How us ticker/lp ticker achieve the same result (no events - nothing happening) - this question is regarding their implementations, if they do something similar (they do not assume upper layer disables interrupts) ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Interrupts cannot be disabled because the ticker interface doesn't expose anything to monitor overflow of the counter.
The workaround is to track overflow at this layer but it requires to have interrupts always on.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The workaround is to track overflow at this layer but it requires to have interrupts always on.
as in - if none, schedule max delta as it is in update_interrupts, and count overflows here in higher layer. I got it now
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will add a block of documentation detailing the algorithm and how we keeps track of overflow.
hal/mbed_ticker_api.c
Outdated
} | ||
|
||
/** | ||
* update the current timestamp value of a ticker. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
when we are supposed to call this ? Whats the requirement?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
User is not supposed to call this function, it is private (static). It can be called whenever the us_timestamp_t held by a ticker_data_t
has to be updated.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My question was from the developer view, once I am about to edit this file, I was not clear when this function is supposed to be called.
hal/mbed_ticker_api.c
Outdated
* interrupt will be set to MBED_TICKER_INTERRUPT_TIMESTAMP_MAX_DELTA us from now. | ||
* Otherwise the interrupt will be set to head->timestamp - queue->timestamp us. | ||
*/ | ||
static void update_interrupt(const ticker_data_t *const ticker) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
update_interrupt vs set_interrupt? Might find a better name for this function?
I believe this is the most important function in this changeset. Where is it then handled that MAX_DELTA is still less than 64bit (if there's event lets say 46bit timestamp set). I assume in the irq handler. I yet have not seen this documented, might be worth adding this here? Something to extend if set_interrupt(MAX_DELTA) then the remaining part is handled ... somewhere... somehow...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
update_interrupt
and set_interrupt
are really different and doesn't operate on the same object
update_interrupt(const ticker_data_t *const ticker)
update the interrupt driving a ticker_data_t object. The update depends on the state of the object and is encapsulated in the function which is not part of the public interface.
ticker_interface_t::set_interrupt(timestamp_t)
set a specific, given timestamp in a ticker_interface.
Do you think of a better name ?
Where is it then handled that MAX_DELTA is still less than 64bit (if there's event lets say 46bit timestamp set). I assume in the irq handler. I yet have not seen this documented, might be worth adding this here? Something to extend if set_interrupt(MAX_DELTA) then the remaining part is handled ... somewhere... somehow...
I'm not sure of fully understand what you want. Can you explain a bit more what you want ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you think of a better name ?
Set new match interrupt ? It might not be match in some sense... or just leave it, I was just not clear what that function does from the name
I'm not sure of fully understand what you want. Can you explain a bit more what you want ?
I'll get back to this, have to reread the implementation again
hal/mbed_ticker_api.c
Outdated
// update the current timestamp | ||
update_current_timestamp(ticker); | ||
|
||
// filter out timestamp in the past |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what does this condition handle - if timestamp to be set is less than the time "now" (thats how we cal this in the comments above) ? might be worth adding a comment or its just me
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
added to the queue and the queue scheduled immediately
I would vote for this, no events are forgotten
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1 for not forgetting events
hal/mbed_ticker_api.c
Outdated
} | ||
|
||
void ticker_insert_event_us(const ticker_data_t *const ticker, ticker_event_t *obj, us_timestamp_t timestamp, uint32_t id) { | ||
/* disable interrupts for the duration of the function */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
prefer to have a reason why you are disabling interrupts, its clear we enter/exit critical section. same for the comment above (update the current timestamp - function name is the same to a reader). A reader is interested why there's a need for critical section - what we are protecting here and why
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ticker API is thread safe and interrupt safe therefore access to the ticker
has to be protected from external modifications.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was just referring there that the comment either can be removed (obvious that theres critical enter/exit) or we specify a reason why its under critical section. same for the below (update the current time stamp - function name says it).
One question - with this work, if we ever get HAL tickers to count overflows, wont be much work to add it in (hypothetically speaking) ? now that we have 64bit timestamp |
If the ticker interface provides a function returning the number of time the counter has overflowed then it may simplify the code in |
bump @pan- Status? |
@pan- Could you rebase? and maybe tell us what's up with this PR (status). |
- A new 64 timestamp type has been added: us_timestamp_t. - Changed type of timestamp in ticker_events iinto us_timestamp_t. - Event queue now have a to store a current, absolute timestamp. - Add alternative versions of ticker_insert_event and ticker_read which accept in input us_timestamp_t. - Add documentation explaining the limitation and behavior of ticker_read and ticker_insert_event.
The Timer implementation has been refactored to take advantage of this implementation as the base for all functions reading the time elapsed.
* update_interrupt renamed into schedule_interrupt * update_current_timestamp renamed into update_present_time * ticker_event_queue_t::timestamp renamed into * ticker_event_queue_t::present_time * Fix doxygen comments in ticker_api.h * Update comments internal comments in mbed_ticker_api.c
Lets throw a nightly on this to pickup and run the newly added tests against alllll the boards. /morph test-nightly |
Result: FAILUREYour command has finished executing! Here's what you wrote!
OutputTest failed! |
@pan- Can you have a look a the failures? NCS fails ticker tests with this changeset? |
|
insert_absolute. With this patch, event insertion should be more precise.
* Initialization clear interrupt status * Remove state in management of interrupt * Handle timestamp in the past * Handle current seconds, even if out of the relative timestamp. * Simplify interrupt handling logic.
@sg- @geky @0xc0170 The fault was on the NCS36510 low power ticker driver, the lp ticker logic was flawed, didn't handle many cases (immediate event, conversion timestamp into seconds counter, ...) and didn't prevented invalid write of the peripheral registers. |
/morph test-nightly |
Result: SUCCESSYour command has finished executing! Here's what you wrote!
OutputAll builds and test passed! |
When initializing the RTC on Kinetis devices, handle the case where the time overflow interrupt is pending and the case where the time alarm flag is pending. These flags persist across reset and if not handled will cause a crash when powering up the low power ticker. This problem manifested as a lp_ticker test failure on the K22F and K64F on CI only when running a nightly. This problem has been present but was made obvious by PR ARMmbed#4094 which configures all tickers to interrupt at least every MBED_TICKER_INTERRUPT_TIMESTAMP_MAX_DELTA (~31 minutes). This caused the RTC alarm to fire 31 minutes after the lp_ticker or lp_timeout test and caused the next run of the lp_ticker test to crash on boot.
When initializing the RTC on Kinetis devices, handle the case where the time overflow interrupt is pending and the case where the time alarm flag is pending. These flags persist across reset and if not handled will cause a crash when powering up the low power ticker. This problem manifested as a lp_ticker test failure on the K22F and K64F on CI only when running a nightly. This problem has been present but was made obvious by PR #4094 which configures all tickers to interrupt at least every MBED_TICKER_INTERRUPT_TIMESTAMP_MAX_DELTA (~31 minutes). This caused the RTC alarm to fire 31 minutes after the lp_ticker or lp_timeout test and caused the next run of the lp_ticker test to crash on boot.
@@ -44,9 +44,12 @@ class TimerEvent { | |||
// The handler called to service the timer event of the derived class | |||
virtual void handler() = 0; | |||
|
|||
// insert in to linked list | |||
// insert relative timestamp in to linked list |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess this was meant to be "relative to the 32-bit cycle" rather than "relative current time". But later contributors assumed the later, and it's only addressed by #14005.
Description
This patch add support of 64 bit us timestamp in the HAL ticker API.
As a result it is possible to schedule events in more than 2147 seconds as it was previously the case.
The class Ticker, Timer and Timeout takes advantage of this new possibility.
Status
READY
Migrations
If this PR changes any APIs or behaviors, give a short description of what API users should do when this PR is merged.
NO