Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 9 of 9

Thread: Interrupts and Priority, missing function calls

  1. #1
    Junior Member
    Join Date
    Nov 2020
    Posts
    3

    Interrupts and Priority, missing function calls

    I am trying to measure capacitance with a LC oscillator. I'm using a timer interrupt at 1Hz to display the measured value, and an attached interrupt on my oscillator output (~1MHz) on digital pin 20 to count pulses for the LC frequency.

    The sketch works, but occasionally it appears to miss a call from the timer interrupt, causing the calculation to be off by almost exactly a factor of 2X frequency I expect, making me think the timer interrupt call was missed. I have set the timer interrupt priority to 0, the highest by my understanding so I would expect that what's happening is the timer interrupts occurs during a pulse input and it's just missed?

    Circuit diagram and code (also below): https://github.com/bungernut/Teensy_...LCCapMeter.ino
    It would be ok to have a few extra pulses counted but why does the timer interrupt not always get called?
    What is the best way to run two interrupts where one is high rate and the other is high priority?
    Is there a better way to count pulses without an interrupt that would not interfere with the timer interrupt?

    Code:
    volatile uint32_t counts;
    IntervalTimer myTimer;
    double capF;
    const double indH = 0.001;
    const double twoPi = 6.283185;
    
    void setup() {
      Serial.begin(115200);
      /* //myTimer.begin(function, microseconds); */
      myTimer.priority(0);
      myTimer.begin(dispCounts, 1000000);  // run every 1 seconds
    
      pinMode(20, INPUT);
      attachInterrupt(digitalPinToInterrupt(20), doCount, FALLING);
    }
    
    void doCount()
    {
      counts++;
    }
    
    void dispCounts()
    {
      capF = 1.0 / (pow( (double)counts/1000000.0 * twoPi ,2) * indH) ; 
      Serial.println(capF);
      counts = 0;
      
    }
    
    void loop()
    {
      while (1);
    }
    Last edited by bungernaut; 11-03-2020 at 07:24 PM.

  2. #2
    Senior Member
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    1,311
    The cast to double might not be atomic thus it might get interrupted by doCount which could lead to weird effects. For a quick test you could disable interrupts during the cap_F calculation.

    Edit: Sorry, that is nonsense I didn't realize that you have the timer interrupt priority at 0. So it can't be interrupted by doCount()...
    Last edited by luni; 11-03-2020 at 07:38 PM.

  3. #3
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    13,142
    Since both func()'s are interrupts - placing both at same priority would not allow them to interrupt each other but queue either for entry after when the other is active.

    IIRC default priority for pin interrupt is 128? So try :: myTimer.priority(128); // match pin interrupt priority value of ???

  4. #4
    Senior Member
    Join Date
    Aug 2013
    Location
    Gothenburg, Sweden
    Posts
    340
    If dispCounts interrupts doCounts while the counts++ is happening, then the resetting of counts in counts = 0; might not happen.
    Problem is that both interrupts both reads and writes counts.

    Perhaps use a shared volatile flag time_to reset_counts that is set in dispCounts and reset in do Counts. So its only read in one of the interrupts and only written in the other.

  5. #5
    Senior Member
    Join Date
    Jul 2020
    Posts
    544
    There's a perhaps better approach to this - don't reset counts at all. Use it just like the output of millis() or micros() and
    subtract the previous value from the current value to determine how many counts have happened in the intervening
    period.

    The benefit of this is several different bits of the code can use counts for different reasons without
    breaking each other as there's only one thing ever changing it.

    Code:
    volatile uint32_t counts = 0 ;  // explicitly initialize to zero.
    
    void doCount()  // as before, but its the only code that writes to counts
    {
      counts++;
    }
    
    
    void dispCounts()
    {
      static volatile uint32_t previous_counts = 0 ;
    
      uint32_t my_counts = counts ;  // assumes reading uint32_t is atomic...
      uint32_t counts_since_last_time = my_counts - previous_counts ;
      previous_counts = my_counts ;
    
      capF = 1.0 / (pow((double)counts_since_last_time/1000000.0 * twoPi ,2) * indH) ; 
      Serial.println(capF);   // is this safe in a timer interrupt?  
    }
    Note counts is only read once to a local variable, that's vital.

  6. #6
    Junior Member
    Join Date
    Nov 2020
    Posts
    3
    Quote Originally Posted by defragster View Post
    Since both func()'s are interrupts - placing both at same priority would not allow them to interrupt each other but queue either for entry after when the other is active.

    IIRC default priority for pin interrupt is 128? So try :: myTimer.priority(128); // match pin interrupt priority value of ???
    This was great advice already. With this simple fix I have not see a single instance of a problem.

    I will look into the other replies for science.

  7. #7
    Junior Member
    Join Date
    Nov 2020
    Posts
    3
    Quote Originally Posted by mlu View Post
    If dispCounts interrupts doCounts while the counts++ is happening, then the resetting of counts in counts = 0; might not happen.
    Problem is that both interrupts both reads and writes counts.

    Perhaps use a shared volatile flag time_to reset_counts that is set in dispCounts and reset in do Counts. So its only read in one of the interrupts and only written in the other.
    Ok, starting to get a sense of my incorrect assumption. Unlike the documentation by Arduino the Teensy3.2 implementation allows interrupting an interrupt?
    This would explain why setting them to the same priority worked...

  8. #8
    Senior Member+ Frank B's Avatar
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    7,571
    Quote Originally Posted by bungernaut View Post
    Ok, starting to get a sense of my incorrect assumption. Unlike the documentation by Arduino the Teensy3.2 implementation allows interrupting an interrupt?
    This would explain why setting them to the same priority worked...
    On Teensy (Arm Cortex), Interrupts with the same priority are processed in a "Round-Robin" style. They can be interrupted by a higher-priority interrupt.

  9. #9
    Quote Originally Posted by bungernaut View Post
    I am trying to measure capacitance with a LC oscillator. I'm using a timer interrupt at 1Hz to display the measured value, and an attached interrupt on my oscillator output (~1MHz) on digital pin 20 to count pulses for the LC frequency.
    The more typical way of doing this would be to use a timer in capture mode. That way it does the pulse counting for you.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •