I have an encoder that fires ~54000 interruptions per second. This is way too fast for my arduino uno. But I'm trying to see what I can get from it anyway. For science.
unsigned long tickACount = 0;
unsigned long tickBCount = 0;
void myInterrupt(){
tickACount++;
tickBCount++;
}
Then in my main loop, every second I print tickACount
and tickBCount
.
I can see my arduino is able to handle only about 2050 interrupts per second. No surprise here.
What surprises me, is that tickACount
and tickBCount
have different values! tickBCount
is consistently higher that tickACount
.
Ok now I switch them to volatile. And according to the documentation, volatile only makes sense for 8bit values. The counts will eventually overflow but it doesn't really matter. I just want to see if those two variables are still different.
volatile uint8 tickACount = 0;
volatile uint8 tickBCount = 0;
void myInterrupt(){
tickACount++;
tickBCount++;
}
The result is that the two values are still different.
Also, wrapping them into some ATOMIC
macro does not help.
From what I read, interrupts cannot be interrupted.
And beside, if my interrupt was aborted midway, then tickACount
would be higher than tickBCount
, not the other way around.
Therefore, what can be the explanation for those two variables to be different?
Thank you for any idea!
1 Answer 1
54000 interruptions per second [...] is way too fast for my arduino uno
Your test is probably flawed. My Uno does handle that interrupt rate with no issues. See my test code below.
my arduino is able to handle only about 2050 interrupts per second
You are probably doing something wrong, like blocking interrupts for too long, or using a library that does so.
What surprises me, is that
tickACount
andtickBCount
have different values!
As previously stated in comments, this is not the case. Instead, the counters have been incremented while you were printing them.
And according to the documentation, volatile only makes sense for 8bit values.
Either the documentation is grossly wrong, or (most likely) you have misread it.
From what I read, interrupts cannot be interrupted.
This is indeed the default behavior. You could change it, by issuing
interrupts()
within the interrupt handler, or by declaring an ISR as
ISR(XXX_vect, ISR_NOBLOCK)
{
...
}
but that is seldom done.
Below is my test code. I used Timer 2 to generate a square wave on pin 3, which is both a PWM pin (OC2B) and an interrupt pin (INT1). The PWM frequency is about 54.054 kHz.
const uint32_t PRINT_PERIOD = 1e6; // print counts every second
struct TickCounts {
uint32_t tickA;
uint32_t tickB;
};
volatile TickCounts rawCounts;
void myInterrupt() {
rawCounts.tickA++;
rawCounts.tickB++;
}
// Atomically read both counts.
static TickCounts getCounts() {
TickCounts counts;
noInterrupts();
counts.tickA = rawCounts.tickA;
counts.tickB = rawCounts.tickB;
interrupts();
return counts;
}
void setup() {
// PWM at 54 kHz on OC2B = PD3 = INT1
DDRD |= _BV(PD3); // pin PD3 as output
OCR2A = 37 - 1; // period = 37 * 0.5 us = 18.5 us
OCR2B = 37/2 - 1; // duty cycle ~ 50%
TCCR2A = _BV(COM2B1) // non-inverting PWM on OC2B
| _BV(WGM20) // mode 7: fast PWM, TOP = OCR2A
| _BV(WGM21); // ditto
TCCR2B = _BV(WGM22) // ditto
| _BV(CS21); // clock at F_CPU/8 = 2 MHz
Serial.begin(9600);
attachInterrupt(1, myInterrupt, RISING);
}
void loop() {
static uint32_t last_time_printed;
if (micros() - last_time_printed >= PRINT_PERIOD) {
last_time_printed += PRINT_PERIOD;
TickCounts counts = getCounts();
Serial.print(counts.tickA);
Serial.print(" ");
Serial.println(counts.tickB);
}
}
And here is the output:
54053 54053
108107 108107
162161 162161
216215 216215
270269 270269
324324 324324
378377 378377
432431 432431
486485 486485
540539 540539
...
tickCountB
>tickCountA
. The possibility oftickCountB
being incremented during the 2 prints hasn't come to my mind. I guess that's experience!