Hello all,
I've been stumped by this for a while before an apparent solution. Here goes:
Pro micro 32u4
DS3231 RTC with DS3231 library
EM406 GPS module on software serial with SoftwareSerial library
Serial1 (onboard) to nextion display. no library
Timer4 (2kHz) interrupt driving 2 stepper motors with about 60 lines of code running in interrupt.
USB for programming and serial debugging.
Problem: Occasional failure of interrupt routine where target counters and actual counters are not properly compared.
Traced to random fail of RTC update from gps. Disabling GPS update of RTC prevented the problem
Only solution thus found: Enclose RTC update code in cli() sei().
Observation: Disabling interrupt completely did not change random update failures. Removing serial debugging had no effect.
Question: Could interaction between library use of interrupts cause this problem and is the solution optimal.
Hope someone can offer some insight on this.
Code is rather lengthy but I will supply it if asked. I think this is more of a general question right now.
Thanks Morgan S. Was wondering how long that would take! Anyway, here is the code to bore you with:
Oops; exceeded 9000 character limit.
I have attached file for you.
I said it was lengthy...
Serial printing with interrupts disabled is NOT a good idea.
Which RTC and library are you using? Most are I2C devices, which require that interrupts be enabled to work. By disabling interrupts, you've ensured that the RTC is never updated (which it never will be anyway).
Hi Paul,
Thanks for looking.
The disable gps update flag was deliberate. Sorry for leaving it in that state. It was so I could prevent gps updates while I manually set the RTC time for testing.
Ok. Serial prints are outside the disabled interrupt area, but makes no difference. Does this imply that Serial prints don't use interrupts, or do they first enable them for their own use?
I don't understand your comment about the array pointer incrementing not being a good idea. How else do I build the array?
The DS3231 library I used is attached. (from Rinky Dink)
More background: Each second, the calculated target for each hand drive is compared with the number of pulses since each hand passes it's 12 o'clock sensor. Pulses are then fed at the interrupt rate until a match is achieved. Pulses are then sent at 10/12 pulses per second to the hour drive and 10pps to the minute drive. Hence the hands chase and then track the real time. (counters are 0 to 35999 due to 180:1 gear ratio on the motors.(timing belts actually)) It is a rather large clock...
All this means the clock works without any manual intervention. On power up the hands go to 12 o'clock position and then chase the time around the dial and then follow it. I will add code to make hands go backward if that is the shortest way to the correct time.
What appears to be happening is that occasionally the hand counter end up greater than the target counter which then makes the hand take off to chase the time around the clock face again. Time flies, literally!
Certainly disabling the gps update stops the problem.
Hmm. I don't think the cli/sei I added did anything anyway. Still not behaving.
Does this imply that Serial prints don't use interrupts, or do they first enable them for their own use?
Serial.print() DOES use interrupts, but, because so many fools try using Serial.print() in interrupt service routines, the print() method in the HardwareSerial class has been bloated (I mean modified) to check whether interrupts are enabled, or not, and, if they are not, to call the interrupt handler directly, to shift the required number of bytes out so that it can write to the buffer.
I don't understand your comment about the array pointer incrementing not being a good idea.
I did NOT say that. I said that writing to the array, and then incrementing the pointer, even if that means writing beyond the end of the array was not a good idea.
Ok links coming..
Thanks for Serial.enlightenment. I will bear that in mind.
And now I see that unless gpsRxPtr++ is limited by recognising the end of string marker being in the expected place it could increment beyond the allocated array size and screw things up. Thanks for the pointer.
Have added trap:
if (gpsSerial.available())
{
gpsTemp = gpsSerial.read();
if (gpsTemp == 36) // detect start of sentence.
{
gpsStartFlag = 1;
gpsRxPtr = 0;
}
gpsData[gpsRxPtr] = gpsTemp; // store incoming sentence.
gpsRxPtr ++;
if(gpsRxPtr>40)
{
gpsRxPtr=0;
gpsStartFlag = 0;
}
if (gpsTemp == 10) // detect end of sentence. Process the result
{
gpsStartFlag = 0;
Some progress. Analysing serial debug shows that the calculated target is not always correct. It some times is higher than intended and then reverts to the correct calc on the next second. This is what is causing the runaway hand travel.
Maybe the DS3231 is beginning to do its own time update as the gps forced update is taking place.
But there seems no way to prevent DS3231 from free running with this library.
I will try to rewrite the registers with the same values after a short interval to prevent the free running of the rtc.
Postscript: That seems to have fixed it. I just updated the rtc twice in succession. The extra few microseconds was enough
to prevent the rtc from starting its own update before the next gps update.
Its been running for some hours and no fault yet. So it looks like the problem was the DS3231 starting to output time and then being overwritten by gps update. Not an interrupt problem at all!
Does anyone know of a DS3231 library where the clock can be stopped and started via command? That would offer one solution.
Thanks to Paul for hint/insight.
Problem solved.
Why do you have an RTC at all, since you have a GPS?
One of the more-popular time libraries works without an RTC. I use it with my GPS because it has good date-time conversion functions and I don't use it to time anything. With no RTC, it uses millis() and can accept regular correction from GPS (or anything) seamlessly.
As far as wanting to use both GPS and RTC, it is for maximum autonomy. Just a personal thing. Also indoors the gps reception is not very reliable and also having the RTC seemed the way to go while developing. I did have a software clock running but then replaced it with the RTC for its greatly increased accuracy. There will be a dedicated solar panel and battery to maintain the system with one minute motion updates to conserve power. Sadly, plutonium backup batteries appear to be out of stock until further notice.
A look at the DS3231 data sheet show that the clock can't be turned off while powered from Vcc. (page 13 data sheet)
However, it can be in battery mode, This would involve switching Vcc to the device and.....all too messy. There may be another way, but what I have seems valid. (24hrs and still no fault)