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/blob/main/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:
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:
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 ???
 
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.
 
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.
 
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.
 
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...
 
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.
 
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.
 
Back
Top