I opened a new thread about using a WWVB receiver to calibrate the Aging register:
https://forum.arduino.cc/t/wwvb-decoder-software/1116490
but further into that thread switched over to discussing using the PPS signal of a GPS module instead. Since I've ended up using the GPS for this, not WWVB, I'd like to bring the discussion back here to present what I've developed for GPS so far, and ask about something that's a bit puzzling.
So to bring things up to date, I bought the GPS module and a 28db antenna from Amazon:
https://www.amazon.com/dp/B07P8YMVNT
https://www.amazon.com/dp/B07DMXGW5J
I got the "big" antenna because a number of reviews of the GPS module complained that the included antenna was no good. In any case,with the big antenna I get good reception indoors on the second floor, which is what I wanted. When first booted up the module takes up to 30 seconds to lock in enough satellites to begin the PPS signal, which goes high for 100ms once every second. I've also looked at the serial data, and it's pretty much error-free. So whoever made the module, it seems to work well, at least with the 28db antenna.
On the RTC side I have one module marked DS3231SN that turns out to be a real DS3231SN. And I have another one marked DS3231M which is indeed that. Then I have a third marked DS3231SN that is in fact a DS3231M. No, that's not right. It's not even a real M because Maxim would never have done that. So its just a complete fake that seems to work like an M.
Anyway, the idea is to find the Aging setting that makes the RTC clock run at the same rate as the GPS. I enable the RTC's 1Hz squarewave output, about 1/2 second earlier than the PPS. Then I measure the number of 16MHz CPU cycles that take place between the two, which of course is about 8 million. Then looking at two such readings taken 5 minutes apart, I can tell whether the RTC is gaining or losing time relative to GPS, and by how much. I divide the difference by what the datasheet says is the effect over 5 minutes of a +/- 1 change to the Aging value, and change Aging accordingly. The first adjustment gets it very close to what ends up being the final value, but I can run it for a number of 5-minute cycles to be sure. Of course it's never going to be perfect because one value will run just a little fast, but +1 will be just a little slow. So you just get as close as you can, and pick one.
I run Timer1 in normal mode at full speed (no prescaler), and accumulate overflow interrupts in a variable. That's in effect a 24-bit timer. After a GPS triggered capture and interrupt, I take the timer readings, then stop the timer and clear its count and the variable count. Then when the RTC squarewave interrupts, it just start the timer. The millis interrupt on Timer0 is disabled so it won't interfere.
I'll post the sketch in the next post. If anyone has a GPS with a PPS output, and any DS3231 modules, I hope you will experiment and report what results you get.
The thing that I'm puzzled about is the datasheet spec for how much a change of the LS bit of the Aging register changes the internal clock. The M datasheet says this is .12 ppm at 25C, which is 576 cycles over 5 minutes at 16MHz. Indeed, when I get the comparison from the first two readings 5 minutes apart, I can divide the difference by 576, and I get a new aging value that is very close to the final optimal value - usually +/- 1.
The datasheet for the SN says it's .10 ppm, which would be 480 cycles. But on my one genuine SN example, it turns out to be .055 ppm. or about 264 cycles. That's the divisor that gets me close to the final answer on the first comparison. But I don't know if that's true just for my SN, or true for all of them. Actually, it would be good if the lower number is valid for all because it means you can get that much closer to perfect time. If the most you could be fast or slow is .055 ppm, that would be 1.7 seconds per year all else being equal.
I had to deliberately set the Aging value of the SN off a good bit (+50) to test the divisor. That's because Aging was at zero by default, and the final optimal value was +1. But the Ms were different. Also zero by default, their optimums were -44 and -19, so off a good bit. So it may turn out that only Ms will benefit materially from this Aging optimization.
In case anyone is interested, my genuine SN is one I recently bought, which is surprising. It comes on a circular board, with no EEPROM, no"charging" circuit, no LED and no pullup resistors (but holes for the SDA and SCL pullups). But unfortunately the battery holder is for a CR1220, which has about 1/6 the capacity of a CR2032.
https://www.ebay.com/itm/401482226870?var=671154997502
I'll put the code in the next post.