Calculating time between falling edges

I would like to calculate the time between the last two falling edge on a pin.

For this case here is a signal snapshot,

image

#define DRDY_PIN 8
#define MCLK_PIN 7

void setup() {

  SPI.begin();
  
  Serial.begin(9600);
  while (!Serial) {}
  
  Serial.println("Starting");

  pinMode(DRDY_PIN,INPUT);
  
  analogWriteResolution(4);
  analogWriteFrequency(MCLK_PIN, 8000000);
  analogWrite(MCLK_PIN, 7);

  attachInterrupt(digitalPinToInterrupt(DRDY_PIN), readySignalRecieved, FALLING);
}



bool dataReady = 0;
unsigned long timeInterval = 0;
unsigned long timeLastUpdate = 0;

void readySignalRecieved() {
  dataReady = true;
  timeInterval = micros() - timeLastUpdate;
  timeLastUpdate = micros();
}


void loop() {

    if (dataReady) {
      dataReady = 0;
      Serial.print("Sample Time Interval: ");
      Serial.print(timeInterval);
      Serial.print("   ( ");
      Serial.print(1000000 / timeInterval);
      Serial.print(" Hz)\t");
      Serial.println();
    }
}

image

I should have a value of 250uS. But the serial monitor is showing differently. its like the micros() are not incrementing or something in between pulses.

Is there something wrong with my code?

And when you qualify the variables "volatile"?

Is there a plan to determine when the LAST two have occurred?

1 Like

There are several problems with your code.

  1. Variables shared with interrupt routines must be declared volatile
  2. Multibyte variables shared with interrupt routines must be protected from modification by the interrupt, when being accessed by the main program.

To analyze a signal with frequency of a few kHz, interrupts are not needed.

1 Like

i just want the time between the last 2 . So for example there a falling edge just happen, i would like to know the time between the falling edge that just happened and the previous one. Just like my first image, i should always get a result of about 248us

Im sorry i dont follow, can you explain further?

Variables used in both interrupt and non-interrupt context must be qualified as volatile, otherwise the optimiser may assume they don't / cannot change.

Also as noted, you cannot access anything wider than a byte atomically, so you must disable interrupts and copy them in non-interrupt context

how can i do this?

there might be blocking code when a falling edge happens, so i think it would be best to process it inside the interrupt. that was what i had in mind.

oh so you mean the ISR actually calculates the correct value, but by displaying it the data being retrieved by Serial.print is already old data??

No, I don't think I mean that.

The processor has an eight bit data bus, so cannot access 32 bit values in a single instruction cycle.
This means the value of the variable could change while it is being read, if interrupts are not disabled.

That is fine, but it does not answer the question of how you know when the last one occurred. OR are you wanting to know the time between ANY two falling edges?

1 Like

It has to be between the latest and the previous. If a new one arrive , it has to be between the new one and its previous

Assuming falling edge A,B,C,D,

When falling edge B is detected, i need to have the time between A and B. when falling edge C is detected, i need to have the time between C and B. When falling edge D is detected i need the time between D and C. So on and so forth.

The falling edges dont have a stable frequency (in my image above it was only a test signal). What is important to me is the time between the current to its previous.

what arduino are you running on?

printing at 9600 bauds to track something happening every 250µS (if I got that right) is somewhat of a challenge...

What if you have more than one interrupt during the time it takes to run the loop()?

1 Like

Im using a teensy 4.1

so i tried placing, everything into the interrupt function (loop is now empty)

void readySignalRecieved() {
  dataReady = true;
  timeInterval = micros() - timeLastUpdate;
  timeLastUpdate = micros();

  Serial.print("Sample Time Interval: ");
  Serial.print(timeInterval);
  Serial.print("   ( ");
  Serial.print(1000000 / timeInterval);
  Serial.print(" Hz)\t");
  Serial.print(timeLastUpdate);
  Serial.println();

}

and also upped the serial rate to Serial.begin(500000);

image

It looks like the ISR is triggering every 2-3uS instead of every 250us. weird...

For the benefit of others trying to follow this thread, please quote the statement you are questioning.

This is exactly wrong. An ISR should be a small as possible.

bool z;   //Global variable

void isrX(){
  z  = true;
}

That is untested code and probably wrong, but you get the point.

Somewhere in your loop, you test z

if(z) {
  //process the interrupt
  z=false;
}

Also, all those Serial.prints take some time which is why you never want Serial.print in an ISR. (And Serial.print itself uses interrupts but your ISR has suspended interrupts).

That is what i did in my very first post, kept the ISR as short as possible and print inside the loop.

As mentioned
You need a critical section in the loop to make a. Copy and work on the copy


void loop() {
  if (gotAFront) {
    noInterrupts();
    // critical, time-sensitive code here
    uint32_t lastCopy = lastFront;
    gotAFront = false;
    interrupts();
     Do stuff with the copy
  }
  // other code here
}

You need volatile variables

No, you are doing math on long ints inside the ISR. Set the flag and leave. Handle the interrupt in loop.

Read this:
https://gammon.com.au/interrupts
Spend some time there and come back with any questions.