1

For clock synchronization I want to implement a pulse counter on the Arduino Nano Every. There are two clock signals at 40-100 kHz, the Nano runs on 20 MHz. Nyquist says we need at least 2 times the sampling frequency, we're at 200 times. So I assume it's possible to program a reliable pulse counter.

Currently, I'm using attachInterrupt(digitalPinToInterrupt(pin), isr, RISING) to count the rising edges on A0 and A1 and periodically display them via Serial.print(). If I have a clock on a single pin, the right amount of edges is counted. But if I connect both pins, each pin counts only 50% to 70% of the rising edges. At the scope, the signal looks fine to me.

volatile unsigned long risingCount0 = 0;
volatile unsigned long risingCount1 = 0;
void isr0() { risingCount0++; }
void isr1() { risingCount1++; }

void setup() { Serial.begin(9600); pinMode(A0, INPUT_PULLUP); pinMode(A1, INPUT_PULLUP); attachInterrupt(digitalPinToInterrupt(A0), isr0, RISING); attachInterrupt(digitalPinToInterrupt(A1), isr1, RISING); }

void loop() { static unsigned long lastPrintTime = 0; int waitSec = 5; if (millis() - lastPrintTime >= waitSec * 1000) { lastPrintTime = millis();

unsigned long c0, c1;
noInterrupts();
c0 = risingCount0;
c1 = risingCount1;
interrupts();

Serial.print(c0);
Serial.print(" ");
Serial.println(c1);

} }

This person says pin 2-5 works for them, but when using digital pins 2 and 3, instead only 10 or 100 results per second are counted. This puzzles me, because the docs also say the digital pins are fine for interrupts. Simultaneous interrupts should be stored as well.

Reading How do interrupts work on the Arduino Uno and similar boards?, I see that, e.g. millis() disables interrupts for a short time, so I assume something is preventing the interrupts from happening. Reducing serial prints also mitigates the issue somehow, but still doesn't fix it. Also, interrupts should just be handled after one another and ISRs writing a single variable should take only single microseconds.

Ideally, there's a solution that continuously measures and prints the result to serial to perform long term measurements. Still, I'm now implementing a version that alternatively prints and measures, to make sure serial prints don't influence the measurement.

Any suggestions for libraries, improving the existing code or all together different approaches are highly welcome. I added project-critique tag as suggested by the help page.

Mo_
  • 111
  • 3

1 Answers1

4

The fact that it works with a single clock suggests your Arduino may simply be overloaded. You may try lowering the clock frequencies: if the counts get correct, then that is your issue.

Two clock signals at 100 kHz means your Arduino has, on average, 5 µs (i.e. 100 CPU cycles) to handle a single clock edge. This may seem like a lot, but it is not that much. Incrementing a one-byte variable from an ISR may need as much as 9 cycles :

  • 2 cycles for saving a CPU register on the stack
  • 2 cycles for loading the variable from SRAM
  • 1 cycles for incrementing the value
  • 2 cycles for storing the result in SRAM
  • 2 cycles for restoring the CPU resister from the stack

For a 4-byte variable (unsigned long), this is already 36 cycles. But then, you are not writing an ISR. The actual ISR is provided by the Arduino core. It has to search for the function pointer you provided as an actual interrupt handler, make sure it is not nullptr and call it. It presumably has to save way more than 4 registers to the stack: all the registers that are “call-used” as per the calling convention. All this is not very efficient. You may want to disassemble the binary to see what it is doing.

I do not think you can make your code significantly faster while using the Arduino core. If you have time to study the datasheet of the ATmega4809, you may want to write your interrupt handlers as actual ISRs, instead of relying on attachInterrupt(). You could even use a hardware counter but, if I understand the datasheet correctly, only the Timer/Counter Type A is suitable for the job, and you have a single instance of it.

Edgar Bonet
  • 45,094
  • 4
  • 42
  • 81