-
-
Notifications
You must be signed in to change notification settings - Fork 8.3k
ports/nrf: add support for time.ticks_ms() #5470
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
Thank your hardworks.
…On Sun, Dec 29, 2019, 03:20 Martin Fischer ***@***.***> wrote:
The nordic port lacks support for a milisecond / microsecond tick
counter (and basically most of the time module functionality..).
The ms tick counter is needed by asyncio and prevents the usage
of this module, which is my primary design goal.
So I had a go and enabled the systick irq with 1msec resolution.
This enables the usage of a 32 bit counter rather than
on relying on the hw's systick timer 24bit width. But it does
add a bit of overhead. 32bit would overflow after 50 days - although
the pyhton return value might be restriceted to only 31 bits (?). 24 bits
take app.
5h to overflow, which might be suitable too.
Inreasing the counter's width to 64bit would eliminate any overflow
handling on the python side, but may add some overhead on passing
this value from C to python (but I'�m not sure how much).
Another option would have grab a separate HW timer unit, which could
probably be used in a better power optimized manner and possibly
could be used without irq's since they are 32bit widht.
However I was reluctant to do this since for some MCU's a timer unit is
precious.
So in summary, it was a suprsing amount of factors to consider for
such a small change. Looking forward to some inputs/comments.
------------------------------
You can view, comment on, or merge this pull request online at:
#5470
Commit Summary
- ports/nrf: add support for time.ticks_ms()
File Changes
- *M* ports/nrf/Makefile
<https://github.com/micropython/micropython/pull/5470/files#diff-0>
(1)
- *M* ports/nrf/boards/pca10059/mpconfigboard.h
<https://github.com/micropython/micropython/pull/5470/files#diff-1>
(2)
- *M* ports/nrf/main.c
<https://github.com/micropython/micropython/pull/5470/files#diff-2>
(14)
- *M* ports/nrf/modules/utime/modutime.c
<https://github.com/micropython/micropython/pull/5470/files#diff-3>
(1)
- *M* ports/nrf/mpconfigport.h
<https://github.com/micropython/micropython/pull/5470/files#diff-4>
(4)
- *M* ports/nrf/mphalport.h
<https://github.com/micropython/micropython/pull/5470/files#diff-5>
(14)
Patch Links:
- https://github.com/micropython/micropython/pull/5470.patch
- https://github.com/micropython/micropython/pull/5470.diff
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
<#5470?email_source=notifications&email_token=AEYAML2AXTJYWHQDTABJYSTQ26YHRA5CNFSM4KARVKN2YY3PNVWWK3TUL52HS4DFUVEXG43VMWVGG33NNVSW45C7NFSM4IDBXXKA>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AEYAML3FQHU6PFQLYKYIJSLQ26YHRANCNFSM4KARVKNQ>
.
|
Thanks a lot for this, @hoihu! In order to get the true feeling of the Reasoning: With its limitations in mind, it might still be possible to use Do not get me wrong, I'm still in favor for this one going in :) |
oh my goodness this information just saved me ;) Thanks.. that's good to know and is apparently different than on the stm32 port (where for example wfi is used within the systick irq handler as part of the So at the moment I have a the new asyncio version in #5332 working on the nrf52. |
Agreed. Essentially this means that you can't use systick with any low power setting (and that might be a popular use case e.g. for a bluetooth beacon etc). I'll have a look into RTCounter. |
Awesome! :)
We might have a common interest here. I plan to replace the sdk_app_timer_mod.c fork from Nordic SDK in my nrf9160 socket support branch with a new MIT licensed RTC timer module. It has been on my TODO list for quite some time, but not yet started on it. If i'm not wrong we are looking for the same thing, right? Some thoughts on what i had in mind: I'm thinking that the |
To recap my scan through the datasheet: There are 3 independant RTC timers. They are 24bit counters with 1/32.768 resolution. Using it for 1msec resolution is possible by setting the divider to 33, but introduces an error of 0.71% (app 25sec/h). Overflows occurs app. after 4.6h and could be handled via irq, if necessary. |
It could overlap, I'm not sure. My primary goal is to get asyncio running on the nrf. This needs to have at least:
some optional things I did for my testing:
ok, similar as the "soft timers" on the stm32? Could be ported from there (see
ok good to know. So maybe could RTC1 be configured for 1msec intervals that |
I somehow like the idea to configure RTC1 as msec timer and RTC2 as a (precise) seconds timer. What I think is a bit tricky to get right are the dependencies of the RTC objects to the various modules... so for example, if ticks_ms is enabled, RTC1 should not be used.. how can we transparently show that to the user? |
I believe we should rule out the use of RTC2. If i recall correctly it is only available in nrf52832, nrf52833 and nrf52840. Other sub-variants of nrf52 lacks it, and also its not present in nrf51, nrf9160 and nrf53.
I'm not sure if i answer the question. I might have misunderstood it. However, I'm thinking that we should re-write the python interface of RTCounter to not use argument 0 (id) as instance number of the physical peripheral to use. But rather auto assign it. Or have a fixed max number of slots used for object creation. The number of c-module users like |
You answered what I meant to ask ;) I'm sorry I'm not native english, so if there is some uncertainty please just ask.
I kind of liked the link for id = hw module number. Maybe add a shim layer on top of those objects, e.g. a kind of an RTCManager that returns state of each RTCobject etc?
Hmm, in the end we'll end up writing C code to initiate RTC1 for msec resolution, either by interfacting/reusing code in But on the other hand - we do have support for the RTC's, in upy. Why bothering with writing C code? Can't we just create a RTC object at boot time (e.g. in boot.py) and then make the time module use the RTC counter? It would most likely also eliminate the need for an RTC manager, since it's pretty clear in uPy code which modules are used and which not. I tried but unfortunately, you can't monkey patch |
actually writing the c code to initalize RTC1 in msec resolution was simpler than I thought. This worked for me and can be placed in
then accessing the counter is as simple as
calling rtc1_init_msec is done within PS: I'm not sure if the above code will work on other nrf platforms (nrf51..) |
f80e8ba
to
3d8c81c
Compare
@glennrub : see force pushed update. It now uses rtc1 as milisecond timer. I checked the datasheet of nrf51 and it seems they have the same RTC interface structure, so I hope this will work there too (I haven't got HW to test with). |
3d8c81c
to
ad0b936
Compare
@hoihu this looks ok to me but I don't have as much experience with the nRF as @glennrub . IMO it's more important to have a good/accurate Is the rtc1 counter 24 bit? That's not a problem but you will need to configure |
I agree on both. It's not possible to reach both with the systick counter (because WFI switches off the CPU clock) and also not with the RTC counter (because it's not very precise for msec intervals). So that leaves only the Timer module. This can be setup to use the (relative low power) 1MHz clock PCLK1M as input and has 32bit width. But I'm not sure if WFI also switches off PCLK1M. this seems to imply that WFI is actually
yes it's 24 bits. good point. From a power saving point of view, the RTC can be used with really low power characteristics (< 0.5uA) but the 1MHz clock is not bad either with 5uA. A very power sensitive application may profit from the RTC. |
by enabling rtc1 as milisecond timer
ad0b936
to
adcf7b9
Compare
cef8d98
to
675ec0a
Compare
So further testing report ;) I did discover the
I tested this with the new asyncio module, and it works (even with |
One thing to think about... There is code in CCR3 where a |
I'd like to proceed with this and would be glad for a feedback. I have a working solution with the ticker's CCR0 module (which I believe has the least dependencies on other modules). To summarize, the proposed approach is to use Timer1's CCR0 module. Timer1 is using the low 1MHz input clock and allows WFI support (important for asyncio). CCR0's IRQ would be calling a tick_handler function which would increment the global msec tick counter. My WIP is working with asyncio runs just fine. My assumption, given the constraints above are that this the most viable way to go. Is this correct? Then I'd like to rename the ticker's module compiler switch to something more general like |
In addition, I'd like to support currently, I'm using the Timer1's CCR1 module to do this like that:
this would eliminate the hard coded
It does use CCR1, so I don't know if that's fine? |
@hoihu , I'm so sorry about the late response. However, i've started to look into a timer replacement for nrf9160 now, and it is natural to start with this! :)
A bit of history; The I have not updated myself to much on In the case i need a similar timer for nrf9160 socket operations (and
@dpgeorge , I agree. However, i guess the case is that you will have a 5mA draw just to keep that value accurate. What is better, accurate timers in application or overall low power? For me it is all use case dependent. Could it be an option add the possibility to boot up the chip in high accuracy (Timer), and on request switch to lower power (RTC)? By adding something like this: then add something like @dpgeorge , @hoihu , Despite my new ideas and questions, i'm thinking we should proceed with what is working (ticker/Timer1). It is a bit tricky putting power and accuracy up against each other, but choosing Timer1 for now will make things move. Or should we investigate more options? |
I think it's only 5uA (micro-amp), which is not much.
I think to start with it'd make sense to have just a compile-time option to select the ticks ms/us implementation, either Timer or RTC. The default could be accurate Timer and a user could rebuild with RTC if needed.
Yes I agree. Let's just get something working. @hoihu I see that this PR is still using RTC1, which is 24-bit, so wouldn't work with wrap around as-is. Are you able to change it to use the Timer1 CCR that you've tested? |
No problem at all. Glad we can continue on this.
I'll look into it and hope that I can provide something this week. |
@glennrub can you confirm that I tried this and it's working with 1. I would include that change in the PR. So far I can configure the time base to be fed by either ticker/timer1 or RTC1(see https://github.com/hoihu/micropython/tree/feat-nrf-ticks-support). I'll cleanup and do some more testing. Probably post it tomorrow. |
I'm pretty sure it's correct as-is. TIMER1 counts at 1MHz but it has 4 channels which trigger at different times and call callbacks. Channels 0, 1 and 2 are "fast" and use units of |
you are of course right, I was slightly confused about However it's not ideal as per now because 1000 (us) is not a multiple of 16.. So the CCR0 irq cannot be fired in precise 1msec intervals. Could we possibly redefine the CCR0's timebase to be scaled in 1usec (line https://github.com/micropython/micropython/blob/master/ports/nrf/drivers/ticker.c#L107)? |
Yeah that should be ok. If anything relies on it being 16us then they can most likely be adjusted to work with 1us. I'd say go for it. |
PR ready to review: #6171 |
Superseded by the implementation in 15574cd |
The nordic port lacks support for a milisecond / microsecond tick
counter (and basically most of the
time
module functionality..).The ms tick counter is needed by asyncio and prevents the usage
of this module, which is my primary design goal.
So I had a go and enabled the systick irq with 1msec resolution.
This enables the usage of a 32 bit counter rather than
on relying on the hw's systick timer 24bit width. But it does
add a bit of overhead. 32bit would overflow after 50 days - although
the pyhton return value might be restriceted to only 31 bits (?). 24 bits take app.
5h to overflow, which might be suitable too.
Inreasing the counter's width to 64bit would eliminate any overflow
handling on the python side, but may add some overhead on passing
this value from C to python (but I'm not sure how much).
Another option would have been to grab a separate HW timer unit, which could
probably be used in a better, power optimized manner and possibly
without irq's since they are 32bit width.
However I was reluctant to do this since for some MCU's a timer unit is precious.
So in summary, it was a surpring amount of factors to consider for
such a small change. Looking forward to some inputs/comments.