0
votes

I have an Arduino Mega application in which I read timing of low-frequency pulses (ca. 10Hz) at various duty cycles.
I use the external interrupt to catch the pulses, add the signal change times information into a 16-bit array[320] that I read back upon completion.
I normalize the time by setting the time of the first upgoing change as time 0. See attached simplified snippet (a working test with Arduino Mega, pin D2).
Problem: The first full cycle after reset reads the timing as expected, while each consequent cycle has only the first pulse ok, while all next pulses' timing is being randomly shifted.
I have tested and tried numerous options, including volatile and interrupt on change only, but always get the same result: First run is OK, next runs are shifted.
Any idea will be highly appreciated.

    /*Program reads input pulses at D2 and builds timing array of the up and 
    down going signals, using change interrupts on pin D2 of Mega
    To run, send array size in hex.
    by Sam Tal [email protected]  Nov 9, 2017
    */
    #define interruptPin 2
    unsigned int dataArraySize;
    unsigned int timeData[320];
    volatile byte state = LOW;
    unsigned int counts = 0 ;      //Changes counter
    unsigned long startTime;       //The first up going interrupt time.
    //==========================================================
    void setup()
    {
      Serial.begin(115200);
      pinMode(interruptPin, INPUT);
    }
    //=========================================================
    void loop()
    {
      if (Serial.available())
      {
        dataArraySize = Serial.read();
        StartCycle();
      }
    }
    //========================================================
    void StartCycle(void)
    {
      Serial.println("Starting cycle...");
      //Reset the time array;
      memset ( timeData, 0, dataArraySize);
      counts = 0 ;
      state = LOW;
      attachInterrupt(digitalPinToInterrupt(interruptPin), Step, RISING);
    }

    //========================================================
    void Step()
    {
      detachInterrupt (digitalPinToInterrupt (interruptPin));
      if (counts == 0)
      {
        startTime = millis();    // Start time of the first rising change.
      }
      if (counts < dataArraySize)
      {
        timeData[counts] = millis() - startTime ;
        counts++;
        attachInterrupt(digitalPinToInterrupt(interruptPin), Step, CHANGE);
      }
      else
      {
        detachInterrupt (digitalPinToInterrupt (interruptPin));
        SendData(timeData, dataArraySize);
      }
    }
     //===========================================================
   void SendData(unsigned int data[] , unsigned int arraysize)
    {
      int f;
      for (f = 0; f < arraysize  ; f++)
      {
        Serial.print(f);
        Serial.print(",") ;
        Serial.println(data[f]);
      }
    }
1
Simillar to @aMike I will also recommend from my personal experience that not to use Serial.print() inside the interrupt handler. Usually, Serial print statements take up to a millisecond to execute. So if you are running time constraint algorithms, never print inside interrupt handlers.svtag
The interrupt handler (ISR) in this case is the Step() function. There is no printing inside that function. Furthermore, the interrupt is disabled each time the ISR is entered. Why do you claim there is a print command in the ISR?samtal

1 Answers

0
votes

The memset() call deals with bytes, but you gave it a count of two-byte integers. So, it's not clearing the entire buffer. Usually we do something like:

   memset(buf, 0, sizeof(buf));

I'm also scared by the Serial.print() inside the interrupt handler. Maybe set a flag there, and call Send() from loop() instead.