Interrupt Latency Problems

Hi,

I've been working on a project for an RC flight controller. I've been using interrupts to determine the PWM input signal but I have noticed that interrupt latency is about 30us - should it be this large? To make matters worse, it is not consistent, sometimes it can be as large as 60us.

The code below shows how I have tested this and attached is a scope output showing the delays. The output should only be high for as long as the ISR takes to fire added to the digitalWrite() time.

#define OUT_PIN 6 
//#define IN_PIN 7 

void myfunc() {
  digitalWrite(OUT_PIN, LOW);
}
void setup() {
  attachInterrupt(0, myfunc, RISING);
}

void loop() {
  digitalWrite(OUT_PIN, HIGH);
  delayMicroseconds(20);
}

In the context of my project this means I cannot accurately determine the length of a pulse.

On top of this the Servo.write() seems to be causing jitter. I think this may be related to the interrupt latency (servo library times the pulses with interrupts). Code below shows a minimal sketch example. When the servo is powered from a bench supply and signal connected to pin 6 the servo jitters about once a second. When signal is connected to an RC receiver, there is no jitter so I don't think the problem lies in the servo but more probably in the code.

#include <Servo.h>

#define OUT_PIN 6

Servo servo;

void setup() {
  servo.attach(OUT_PIN);
  servo.writeMicroseconds(1500);
  }

void loop() {
}

Hi, check the thread that I have started last week. Simply put, you must use mbed functions to get a reasonable performance: Can't read pin value from interrupt - Nano 33 BLE - Arduino Forum

It also mentions how to write Pwm in a better way than using the Servo library.

Check here to see more info about where the problem with Arduino DigitalWrite is: BLE Interference with digitalWrite - Nano 33 BLE - Arduino Forum

To summarise what I believe is a solution to your problem - this this code:

mbed::PwmOut d2(P1_11);

....

d2.period_ms(200);
d2.pulsewidth_us(1000);

and I believe that it will work much better, as this is a native mbed function.

I'm hoping to verify it soon, I just need to borrow an oscilloscope.

Thanks for this, brilliant stuff for the PwmOut - gets rid of all jitter for me.

The mbed interrupt way of doing things seems to be a major improvement as well, latency of 10us (typically), but very ocaasionally takes 35us. Is there a background ISR that could be blocking the one I've set up? (first time with arduino - tell me if I'm being daft...)

As an aside, is 10us the performance you'd expect from this? (unless I've done the maths wrong that's 640 clock cycles...)
EDIT: After reading some of the mbed forums the 10us does seem to be normal, however the occasional 35us does not.

Code I used to test it is below, with pin 2 and 6 connected.

#include <Arduino.h>
#include <pins_arduino.h>
#include <mbed.h>
#include <rtos.h>
#include <PinNames.h>

mbed::InterruptIn sigIn(P1_11);
mbed::DigitalInOut outPin(digitalPinToPinName(6));


void myfunc(void);

void setup() {
 sigIn.rise(mbed::callback(myfunc));
 outPin.output();
}

void myfunc() {
 outPin = LOW;
}

void loop(){
 outPin = HIGH;
 delayMicroseconds(20);
}

Scope traces below shows a typical latency and then a long one.

Any suggestions for fixing this appreciated!

dannickalls:
EDIT: After reading some of the mbed forums the 10us does seem to be normal, however the occasional 35us does not.

ARM-Cortex-M processors have Nested Vector Interrupt Controllers. This means that interrupts with a higher priority can interrupt ISRs of lower priority interrupts. There could be two cases

  • there is an interrupt with a higher priority configured
  • there is an interrupt with the same priority running sometimes when your interrupt fires preventing your ISR from running

FYI: The nRF52840 has 48 interrupts with 3 bits priority = 8 Levels

There are some functions defined like NVIC_SetPriority() in the CMSIS core, but I/you need to some experimenting to figure out how the priorities are currently set and whether it is safe to change them.

Thanks for testing it out! What Klaus said makes perfect sense to me.

Also, try using wait_us() instead of delayMicroseconds(), as wait_us() is native mbed function. I have noticed that it complains heavily about Arduino waits during compile time...

Edit: I've just checked Arduino-mbed wrapper, and delayMicroseconds() is implemented as a simple call of wait_us(). So disregard this post.

Thanks Klaus, your much more knowledgeable view confirms what I suspected...

I'm afraid I don't think I have the knowledge to do a thorough investigation into this, but if I find some spare time I'll certainly have a look... (even if just out of curiosity)

If I filter my results sensibly then the variability in interrupt latency in the mbed ISRs is ok(ish) for my application.