Go Down

Topic: Interrupt Latency Problems (Read 1 time) previous topic - next topic

dannickalls

May 21, 2020, 05:50 pm Last Edit: May 21, 2020, 05:52 pm by dannickalls
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.

Code: [Select]

#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.

Code: [Select]

#include <Servo.h>

#define OUT_PIN 6

Servo servo;

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

void loop() {
}

haplm

Hi, check the thread that I have started last week. Simply put, you must use mbed functions to get a reasonable performance: https://forum.arduino.cc/index.php?topic=684324.0

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

haplm

Check here to see more info about where the problem with Arduino DigitalWrite is: https://forum.arduino.cc/index.php?topic=663776.0

haplm

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.

dannickalls

#4
May 21, 2020, 09:56 pm Last Edit: May 22, 2020, 12:12 am by dannickalls
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.

Code: [Select]
#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!

Klaus_K

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.

haplm

#6
May 22, 2020, 08:02 am Last Edit: May 22, 2020, 10:13 am by haplm
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.

dannickalls

#7
May 22, 2020, 10:59 pm Last Edit: May 22, 2020, 10:59 pm by dannickalls
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.

Go Up