RTC DS3231 millisecond resolution

Hi there, I know there ara plenty examples on internet about this RTC Module, however I haven't found any reliable solution to sync MCU & RTC to the millisecond (or near)

I am considering the best hardware for my project and since I don't have a module in my possession, I am talking about theory.It seems that the DS3231 resets the interrupt every time you save the date so activating 1hz square output, saving the date (from NTP server or whatever) and wait for the next interrupt seems to be a good way to sync to the mills

I would like to know if somebody with this module can confirm if the interrupt timer get reset everytime you save a new date, from datasheet (Page 12) I read this but I'm not sure what exactly means

It's just saying that it's the falling edge of SQW that coincides with the seconds change. What I've been doing to sync milliseconds to the RTC PPS, is connect it to an interrupt capable pin, the ISR just captures the current millis() value. The mainline code can always get the millisecond offset by subtracting millis() from that stored value.

This works but there is a small offset due to interrupt response latency.

A more detailed response would require that you explain more about your project, how the millisecond value is used.

wait for the next interrupt seems to be a good way to sync to the mills

This confuses me. Are you talking about waiting (via polling?) in the main program? If so, you doubly need to explain, that does not sound kosher.

If you can't explain the project, can you please clearly explain your requirement?

Yeah that exactly it's want I want to make, but this way you know how many millis elapsed since you request the Date to the RTC, but you are not in perfect sync with the RTC , example:
You request date and you get (avoid date, for easy reading) 2023....12:00 but the real thing it's the RTC date is 12:00.999 so you are almost 1 second off

I understand, you need to wait to the interrupt to immediately ask for the date, this way you are at .000 or near .000ms of the real RTC date but the success of this depends if interrupt it's every 1 second since you save the Date, or it's an absolut 1 hz rate regardless when you set the date

I need to track how many time (with millis) elapsed from one event to other (interrupts from a sensor) But there may be some resets/power off from the MCU in the middle, so lets say:
1.Sensor interrupt 12:01.560 (store in eeprom)
2.MCU Reset / power off for 1 minute, boot and Ask for date to RTC
3.Sensor interrupt 12:05.360
4. Substract new date - stored date

I need to be in millis sync to RTC in order to calculate exatly the time between both events

You didn't mention power cycles before, but it is okay. Using the method I mentioned, suppose you measure event 1 at 11:59:00 plus 333 ms for example. You store the value. Now you power cycle, reboot happens. When you reboot, the next PPS resets the ISR value. Event 2 comes along, obviously you have the correct seconds value because that is what an RTC does for you, calculate the current millis time as I outlined, and you have both the seconds and milliseconds value for both events.

You also didn't mention sensor interrupts, but that is okay too. However, your sensor ISR must now also capture and store the millis value. Realize that this is not the same as the PPS interrupt, you will need both.

I think understood your first comment perfectly, If i'm not wrong it's to store in a var "last_millis" the value of millis() when the interrupt occurs, then when needed, subtract millis() - last_millis and sum this result to the previus RTC date in order to get the "real" current date

If this is what you meant, I'm missing someting, but this is wrong, the moment you request the date from the RTC it's different the moment you get the next interrupt, that elapsed time it's going to fake the result, you are in sync with the RTC but only at second level

The only scenario I can think is to ask date immediately in an interruption (once time only) in order to get 12:00:00.000 and start counting millis() from that precise moment

It might be good to track the millis() from the 0.500s rising edges, so you don't have the potential race at the seconds change, when you might read the RTC just before, and the millis() just after the interrupt.

Can you explain a little more about this? and What are the 0.500s rising edges?

Reads from the RTC don't affect its timing chain at all. It's only when the seconds are written that it happens.

The only scenario I can think is to ask date immediately in an interruption (once time only)

You can't. You have to keep refreshing the tracking variable due to the inaccuracy of millis(), in turn due to the inaccuracy of the MCU clock.

1 Like

You quoted it from the data sheet, in your first post.

Of course the value returned by millis() will differ after a reset. But that doesn't matter at all, because you should never reference the value at all, only the offset which is calculated.

@DaveX is saying, keep the aggregate time value atomic by not capturing the low order (ms) when the high order (seconds) is rolling over.

As an additional precaution, you should have a validity flag on the captured value since it will be invalid until the first interrupt comes along.

It's very hard to me to explain, I'm going to try with this example: Let's say we already have a DS3231 perfectly synchronised to the thousandth to the Real world clock, for easy understanding we are going to forget about drift, delays, lantency and inperfections, we assume we have a perfect DS3231 synchronised

Now we put it in arduino (or whatever mcu) , we add the interrupt attachament and all stuff and we request the date, we get 12:00:00

After 600 ms, we got an interrupt and we want to print to uart (or send to internet or whatever) what time is it, can you please tell me, with your method, What time is it?

From the RTC, we get 12:00:00. From the ISR we get 600. We calculate 12:00:00 + .600 and get 12:00:00.600

But as I mentioned, you need to wait until the first interrupt and in this example you didn't so it wouldn't work for the first 500ms, doing it according to the rising edge of PPS.

1 Like

Well, now you are adding more logic and that's partly why I said you were wrong, but anway, we are going to wait until the second interrupt, what time it's at the second interrupt?

Oh, for heavens sake. If you say I am wrong you have to explain why better...

Using @DaveX method, you can sync any time after the first interrupt which could arrive from 0 to 999 ms after boot.

This topic needs some clarity & code.

Are you talking about resetting the RTC or reading the RTC?

At the first falling edge interrupt after 12:00:00, the time is 12:00:01.000, at the second falling edge interrupt, it is 12:00:02.000.

But your app probably doesn't care what time it is at the interrupt, it likely cares what time it is when you ask for the time, and that could be 12:00:05.678.

I understand every interrupt it's a "new second" so if we have 12:00:00 and 600ms before we have a new interrupt, that mean 12:00:01.000, I think I understand that your approach is wrong.

Unfortunately mine is years old and it would be too hard to find right now.

You still haven't said why. That is just annoying. We're all technical people here, so you should explain your position.

I told you, with this method, you have to maintain a validity flag in the ISR, initially set to invalid and set to valid as soon as the first interrupt is called.

It could take up to one second after boot, to allow a valid time stamp to be captured. You have to wait for it.

Reading, I don't have code, I don't even have the RTC, I was asking only about the interrupt reset when you set a new date but things have gone off the rails :joy: (my fault)

Can you explain me a little more about this? I'm not an expert, I was thinking the interrupt was a tiny HIGH pulse every second, but it's more 0.5s high, 0.5 low?

I need to track absolute real date rather than relative, power cycles expected so I need to store real word dates (with millis) or atleast Real RTC dates (I know DS3231 it's going to drift sooner or later)

Don't get me wrong, no malice intended
As I said in my first words, I need to be in sync to the RTC as millis level, with you approach as you said the date I would have stored would have been 12:00:00.600 rather than 12:00:01.000

You are, if you possess both the seconds and milliseconds. With my (and DaveX's) method, you do. That is what I understand as "being in sync". If you mean something else, then please explain.

Only in your mind. It's been explained several times now. It's hard to stay on the rails, if the track signals are misread. :slight_smile:

I suggest taking the thread away and thinking about it for a while.