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

RTC timestamp, was not read atomic, which can lead to wrong timestamps. #160

Merged
merged 1 commit into from
Dec 8, 2021

Conversation

systec-ms
Copy link
Contributor

No description provided.

RTC timestamp, was not read atomic, which can lead to wrong timestamps.

Signed-off-by: Moritz Scheuren <moritz.scheuren@systec-electronic.com>
Copy link
Contributor

@hannobraun hannobraun left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, @systec-ms! Looks great, as always.

@hannobraun hannobraun merged commit aca0adf into stm32-rs:master Dec 8, 2021
@adamgreig
Copy link
Member

I saw this PR just after writing a bunch of RTC handling code for another project so maybe it will be useful:

Instead of returning an error, maybe it would be nicer to perform a second read and so always return consistent data?

The RM says (in RM0385 29.3.8 Reading the calendar) that if the APB clock is >= 7x the RTC clock (which is very likely since RTC clock is usually 32kHz) then it's OK to just read TR and then DR: the hardware locks DR after you read TR to ensure you get consistent data. In fact, it's important to always read TR and then DR, otherwise the later read of TR will lock an old value of DR. But, even if the APB clock is extremely slow, you can always read TR, then DR, then TR, then DR, and use the first values if the two TRs match, or the second values if the TRs don't match (as also described in the RM). Seems friendlier than returning an error to the user who has no choice but to now re-read in a loop until it doesn't error.

It looks like the driver should also wait for RSF to be set before taking values in case the user re-reads very soon afterwards too, and clear it after each read. Maybe it would be best to have a single get_datetime() method that does the correct wait-for-RSF, read TR, read DR, clear RSF sequence, and parses the fields, and then convenience methods for reading just seconds/minutes/etc could call that and return the relevant bit. Or just always give the user a full consistent datetime to make sure they don't try and read each part separately and end up with inconsistent data that way anyway...

@systec-ms
Copy link
Contributor Author

systec-ms commented Dec 8, 2021

Instead of returning an error, maybe it would be nicer to perform a second read and so always return consistent data?

Probably yes, I did it that way since the error type was already there.

It looks like the driver should also wait for RSF to be set before taking values in case the user re-reads very soon afterwards too, and clear it after each read.

You are right.

Maybe it would be best to have a single get_datetime() method that does the correct wait-for-RSF, read TR, read DR, clear RSF sequence, and parses the fields, and then convenience methods for reading just seconds/minutes/etc could call that and return the relevant bit. Or just always give the user a full consistent datetime to make sure they don't try and read each part separately and end up with inconsistent data that way anyway...

I agree, but I am unsure which one is better. Returning always a full consistent datetime would conflict a bit with the rtcc trait. Nevertheless, I currently think this would be the best option, and we rebuild the whole thing on the chrono crate.

Also, that every get function sets the calendar clock to 24 hr format with self.set_24h_fmt(); is not superb.

@adamgreig
Copy link
Member

It might also be worth checking the (revamped) time crate which works fine on no_std now and seems more currently maintained, though I'm not sure what the general backstory is between them.

@systec-ms systec-ms deleted the rtc_atomic_read branch December 9, 2021 09:22
@hannobraun
Copy link
Contributor

Thank you for your insight, @adamgreig. I like the idea of only returning a full date/time to ensure consistency. I don't know how whether it's worth diverging from the rtcc traits for this, but maybe an argument could be made to change the rtcc traits.

In any case, I don't have time to implement any of the suggestions (as usual), but I'm happy to review and merge pull requests, in case anyone wants to make further improvements here.

systec-ms added a commit to systec-ms/stm32f7xx-hal that referenced this pull request Dec 10, 2021
* Removed rtcc in favor of time
* Removed get functions in favor of a single get_datetime function
* Takes into account registers synchronization flag
* Always returns a valid time (or panics)

See stm32-rs#160 (comment)

> Instead of returning an error, maybe it would be nicer to perform a second read and so always return consistent data?
>
> The RM says (in RM0385 29.3.8 Reading the calendar) that if the APB clock is >= 7x the RTC clock (which is very likely since RTC clock is usually 32kHz) then it's OK to just read TR and then DR: the hardware locks DR after you read TR to ensure you get consistent data. In fact, it's important to always read TR and then DR, otherwise the later read of TR will lock an old value of DR. But, even if the APB clock is extremely slow, you can always read TR, then DR, then TR, then DR, and use the first values if the two TRs match, or the second values if the TRs don't match (as also described in the RM). Seems friendlier than returning an error to the user who has no choice but to now re-read in a loop until it doesn't error.
>
> It looks like the driver should also wait for RSF to be set before taking values in case the user re-reads very soon afterwards too, and clear it after each read. Maybe it would be best to have a single get_datetime() method that does the correct wait-for-RSF, read TR, read DR, clear RSF sequence, and parses the fields, and then convenience methods for reading just seconds/minutes/etc could call that and return the relevant bit. Or just always give the user a full consistent datetime to make sure they don't try and read each part separately and end up with inconsistent data that way anyway...

Signed-off-by: Moritz Scheuren <moritz.scheuren@systec-electronic.com>
@systec-ms systec-ms mentioned this pull request Dec 10, 2021
@systec-ms
Copy link
Contributor Author

See #162.

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

Successfully merging this pull request may close these issues.

None yet

3 participants