Interurrpt priority....maybe?

Hello all,
I've been stumped by this for a while before an apparent solution. Here goes:

  1. Pro micro 32u4
  2. DS3231 RTC with DS3231 library
  3. EM406 GPS module on software serial with SoftwareSerial library
  4. Serial1 (onboard) to nextion display. no library
  5. Timer4 (2kHz) interrupt driving 2 stepper motors with about 60 lines of code running in interrupt.
  6. 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.

I'm sure the problem is in the code you didn't post.

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...

GPS_test_1.ino (17.6 KB)

homeOnPowerup.ino (590 Bytes)

Hour_master_counter.ino (1.13 KB)

lightingControl.ino (483 Bytes)

nextionDisplay.ino (36 Bytes)

timeZoneDST_Correction.ino (5.21 KB)

    gpsData[gpsRxPtr] = gpsTemp;    // store incoming sentence.
    gpsRxPtr ++;

even if there isn't room. NOT a good idea.

        gpsUpdateFlag=1;
        if(gpsUpdateFlag==0)

What are the odds that the if statement will evaluate to true?

CanIsuggestthatyougetyourspacekeyfixed?

        Serial.print(swTimeRegister[0]);
    Serial.print(":");
    Serial.print(swTimeRegister[1]);
    Serial.print(":");
    Serial.print(swTimeRegister[2]);
sei();

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.

Sorry here is the file:

DS3231.pdf (111 KB)

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.

The DS3231 library I used is attached

To what? Not your reply.

Sorry here is the file:

We need to see (links to) the .h and .cpp files, not the user manual.

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;

DS3231.cpp (9.71 KB)

DS3231.h (3.04 KB)

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.

   gpsUpdateFlag=0;
        if(gpsUpdateFlag==0)
        {
        
        rtc.setDate(swTimeRegister[3], swTimeRegister[4], swTimeRegister[5]);
        rtc.setTime(swTimeRegister[0], swTimeRegister[1], swTimeRegister[2]);
        rtc.setDate(swTimeRegister[3], swTimeRegister[4], swTimeRegister[5]);
        rtc.setTime(swTimeRegister[0], swTimeRegister[1], swTimeRegister[2]);
        
        }

Well, confidence is building; it is certainly functioning longer than before. I will know for sure in the next half hour...

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.

Sorru, I forgot the exact name of that library.

leolfs:
Does anyone know of a DS3231 library where the clock can be stopped and started via command? That would offer one solution.

Have you looked at the code of the library to see if it would be hard to add a command like that ?

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)