nRF52840 express problem with micros() in ISR

Please tell us which board you are using.
For CircuitPython issues, ask in the Adafruit CircuitPython forum.

Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.
Locked
User avatar
jojazz
 
Posts: 2
Joined: Mon Nov 22, 2021 2:04 pm

nRF52840 express problem with micros() in ISR

Post by jojazz »

Hi,

I ordered some Feather nRF express boards. I use the board with an ultrasonic sensor (HC SR-04) for continuos distance measuring (this is only one task in a more complexe project). The sensor works fine with the pulseIn() function. To avoid the timeblocking, caused by pulseIn() I wanted to substitute the pulseIn by reading the sensors result via an ISR. The ISR shall generate a timestamp when the the "echo-Pin" - pulse starts and one when it ends. The difference of both is the required pulse-duration, related to the distance. I kept the ISR very small to avoid timer overflow problems. I am aware that using micros() in ISR can become problematic.

After a longer investigation I came to a curious result (not a solution...): The measured duration jumps in steps of 976 microseconds. When cross-checking by continous scanning the echo-Pin without ISR, suddenly also the ISR worked properly. Even, if I comment out the recording of the micros, it works, as long there is a continous scan of the echo-Pin. As soon I remove the echo-pin scanning, the 976 us steps return. Crazy! There might be a bug in the core (wiring.h / .c or somewhere else). Here my test-sketch for this issue:

Code: Select all

#include <Wire.h>

#define trigPin 5 
#define echoPin 6 

static volatile unsigned long pulseStart, pulseStop;
static volatile boolean pinHL;

void setup() {
  
  pinMode(trigPin, OUTPUT); // Sets the trigPin as an OUTPUT
  pinMode(echoPin, INPUT); // Sets the echoPin as an INPUT
  dwt_enable();
  Serial.begin(115200);
  attachInterrupt(digitalPinToInterrupt(echoPin), ultrasonic_interrupt, CHANGE);
}

void ultrasonic_interrupt(){
  pinHL ? pulseStop = micros() : pulseStart = micros();      // detect falling or rising edge -> 
                                                              // start or stop of the pulse; 
                                                              // pinHL state is before the interrupt;
  pinHL = !pinHL; 
}

void loop() {
  unsigned long delta;
  
  pinHL = LOW;
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(200);
  digitalWrite(trigPin, LOW);  // Pulse to start the measurement of the sensor

  while(!digitalRead(echoPin)){;}
  // pulsStart = micros();
  while(digitalRead(echoPin)){;}
  // pulsStop = micros();
  delay(20);

  delta = pulseStop - pulseStart;
 
  Serial.print(" start: ");
  Serial.print(pulseStart);
  Serial.print(" stop: ");
  Serial.print(pulseStop);
  Serial.print(" delta: ");
  Serial.println(delta);


}
This sketch provides correct values, but it blocks the time (by the useless echo-pin scanning) like the pulseIn does. Removing the permanent echo-pin scanning leads immediately to 976 us steps. ( pulse duration results limited to : 42 us, 1018 us, 1995 us, 2972 us, 3948 us, ...). Can someone help?

User avatar
jojazz
 
Posts: 2
Joined: Mon Nov 22, 2021 2:04 pm

Re: nRF52840 express problem with micros() in ISR

Post by jojazz »

after further investigations, I tracked down the problem.

Following post describes a similar problem:
viewtopic.php?f=53&t=162235&p=802573 (Adafruit Feather nRF52840 Express - micros() counter function resolution very low)
which was transferred to github.
https://github.com/adafruit/Adafruit_nR ... issues/451
Reason for the problem: micros() was clocked by the RTC (much too slow for microsecond resolution). This problem was worked on by hathach (github) and he solved it by switching to the DWT counter (as long as availlable).
https://github.com/adafruit/Adafruit_nR ... o/pull/551

After that micros() resolves in usec (provided DTW is enabled), basically... But for me the problem still appeared when I record timestamps via an ISR... but not allways... now I found out, that it seems to happen, when the interrupt is activated during delay() is running. It seems, that delay() is reactivating the RTC mode for micros() and this is how the coarse resolution (976 us steps) is created. delayMicroseconds() seems not to switch to RTC mode. However, after replacing delay(20) by delayMicroseconds(20000), everything works fine. This is a workaround; I recommend that the delay()-forces-RTC-clock-problem can be solved in future.

Hope this post helps other "ISR + micro()"- users with the nRF52840 board.

Locked
Please be positive and constructive with your questions and comments.

Return to “Feather - Adafruit's lightweight platform”