Skip to content

Allow sleepings fractions of a second #23

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

Closed
wants to merge 3 commits into from

Conversation

angelnu
Copy link
Contributor

@angelnu angelnu commented May 24, 2020

Built on PR stm32duino/STM32RTC#25 - cannot be merged before this dependency is merged.

This allows sleeping fractions of a second. I noticed that previously the limit was not only that delay had to be more than 1 seconds but also that the sleep was being rounded to the lowest second. This lead in my sketch to an accumulated error of being "ahead" by several seconds after just one hour.

With this patch and using an external 32 KHz quarz I am able to sleep with not even a second error in the same 1 hour test.

@fpistm fpistm self-requested a review May 26, 2020 08:26
@fpistm
Copy link
Member

fpistm commented May 28, 2020

Hi @angelnu,
I'm currently reviewing your PR an merged the RTC one. How did you test? I guess you have an alarm higher to 1s?

@angelnu
Copy link
Contributor Author

angelnu commented May 28, 2020

I have tested with:

  • alarms in the 20 seconds range (10 min in production) that do not be too precise and worked fine before and after the fix
  • alarms in the 2 second range that need to be very precise in calculating elapse time - they are used to start listening for a Lorawan connection reply. I did verify that the delay is in a 20-30 ms range longer than expected - this is expected due to some delays in the HAL wakeup library. I am working in the best possible way currently to update the system ticks afterwards.
  • less than a second delays. They work, same comments as for the 2 second delays.

The above allows me to keep the system deep sleeping most of the time: before that I had to accept in average 2-5 seconds of active wait per lorawan transmissions. With the current I am down to less than a second and still tuning. The largest challenge left is to get a <1ms error when updating the ticks after sleeping. I am trying with setting the RTC to a rounded second before going to sleep so I can better calculate it the sleep time afterwards. Still more test on this before I propose a PR.

@fpistm
Copy link
Member

fpistm commented May 29, 2020

* less than a second delays. They work, same comments as for the 2 second delays.

OK. anyway, I've an issue with this use case and it seems normal. Did you test with the updated RTC?

@angelnu
Copy link
Contributor Author

angelnu commented May 30, 2020

yes, I did: it depends on the new parameters added by my latest PR to the RTC library.

@fpistm
Copy link
Member

fpistm commented Jun 1, 2020

@angelnu
I'm not sure how you get it working properly as the way subsecond is managed is not correct in the RTC library. It is not properly computed. Moreover the way it is used in the low power library has some restriction. First if you are less than a second and also because the RTS SS mask match is precise for a second( RTC_ALARMSUBSECONDMASK_SS14_10). not that all those issue are mainly related to the synchronous prescaler value. More higher it is more precise will be the subsecond but low power performance will be less.

@angelnu
Copy link
Contributor Author

angelnu commented Jun 1, 2020

@fpistm - you are right -> depending on the epoch at the entry it works or not... I was getting lucky because I was using rounded subseconds but it does not work when I use things such as 491 ms...

So this patch needs more work. Where is the prescaler set? If known I could round the sleep ms to to match. Another option would be to change the prescaler as you say: would it be possible to change it dynamically?

@fpistm
Copy link
Member

fpistm commented Jun 1, 2020

Prescaler is already customizable, this is not the problem, problem is that sub second requires some other management, I will update that.

@mkals
Copy link

mkals commented Jun 29, 2020

+1 for this one, I need a sub-second sleep feature in my latest project. I have tried looking into this all evening, but have not been able to make it work. I'm happy to take another look though, let me know if I can help!

@mkals
Copy link

mkals commented Jun 29, 2020

I do not need accurate sleep-times, just something around 100 ms. Could you share your setup @angelnu when you had this working? I have not been able to replicate despite using your modifications and the subsecond pull request branch for the RTC library.

@fpistm fpistm added the enhancement New feature or request label Jul 3, 2020
@fpistm fpistm added this to the 1.1.0 milestone Jul 3, 2020
@angelnu
Copy link
Contributor Author

angelnu commented Jul 4, 2020

There seems to be differences as well between the L4 and L0 families: my patch works in L4 but it is failing to wake up in L0. I see that @fpistm has marked this for the next milestone so I am not trying to figure it out since most of my projects (new) are on the L4 and only one of my L0 boards in in the drawer until there is better patch.

I also looked at using the TIM for small sleep periods and I think I could get it to work, but I do not like having to use completely different flows since I need to mix short and long delays.

What MCU are you using @mkals ? If you only need 100 ms delays the LTIM might be what you are looking for.

@fpistm
Copy link
Member

fpistm commented Jul 5, 2020

RTC subsecond management is now merged and so now subsecond works properly with alarm.
Next week I will finish this PR.

@mkals
Copy link

mkals commented Jul 5, 2020

I'm using an L0 board, so that might explain why I did not get it working. Thanks for the suggestion about the LPTIM @angelnu, I tried looking into using it, but was not been able to figure out how to use it in the Arduino environment.

Awesome with the progress being made on this @fpistm, really appreciate it! I'll wait to investigate more til the PR is finished.

@fpistm
Copy link
Member

fpistm commented Jul 7, 2020

This PR has been merged in #31.

@fpistm
Copy link
Member

fpistm commented Jul 7, 2020

Note that I've tested with several MCU and for L0, it works well. Here the output of the AlarmTimedWakeup updated example:
image

The required time is 567 ms, note that the precision is linked to the synchronous prescaler and the input rtc clock.

@angelnu
Copy link
Contributor Author

angelnu commented Jul 7, 2020

Impressive @fpistm !

is the actual delay guarantied to be bellow the required value? In your example: do you always get the delay being less than 567?

The motivation for the question is that then a delay could be added after coming back from deep sleep to get the precision down to the ms. Then the lower precision just adds some extra power consumption but not the actual precision.

I will test on the L4 - I might need some days to figure out how to upgrade the sstm32duino in PIO first...

@fpistm
Copy link
Member

fpistm commented Jul 7, 2020

There is no guarantied, it depends the RTC input clock used and the prescaler configured. As mentioned in the STM32RTC:

Subsecond “resolution” depends on synchronous prescaler value. Bigger than this value is, better resolution will get for subsecond.

Moreover in the above example, the Serial print have to be taken in account and also the wake up time and also the time to reconfigure the alarm in the callback.

@angelnu
Copy link
Contributor Author

angelnu commented Jul 7, 2020

I would have expected to take longer based on the serial prints and the RTC having to "step" but your measurement example shows the sleep taking less time (540 ms) instead of 567. I am interpenetrating that right?

For Lorawan having the precision down to the ms is important: at the moment I am depending on the sleep lenght using a delay or deep sleep. Ideally I would always use deep sleep for the mayor part of the delay and add delay to complete the requested precise sleep. For example if the request is to sleep 567 ms then I could deep sleep for 500 ms and then go into an active delay loop until I hit the exact expected ms.

The documentation in STM32RTC does not provide any recommendation or explain the trade offs on picking up a larger prescaller. I see some values are calculated automatically by the library when none provided so not sure if I can come with better values provided by my client code. I will need to read more on the datasheet.

@fpistm
Copy link
Member

fpistm commented Jul 7, 2020

As said it depends how the user code is implemented.
In the example I used it is really not optimum as it required some computation and stuff before reconfigure anyway this is only an example. About the prescaler value it is up to end user to provide a correct one depending of his config and desired stuff.
Using a higher synchronous prescaler value allows a better precision but increase the power consumption.

For example, I've modified the example to use the LSE clock and a synchronous prescaler value of 4095 and I've removed the Serial stuff:

  rtc.setClockSource(STM32RTC::LSE_CLOCK);
  rtc.setPrediv(7, 4095);

With atime=567ms:
image

With atime=25ms:
image

@fpistm
Copy link
Member

fpistm commented Jul 7, 2020

I close this one as it is replaced by #31

@fpistm fpistm closed this Jul 7, 2020
@fpistm fpistm added the duplicate This issue or pull request already exists label Jul 7, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
duplicate This issue or pull request already exists enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants