Counting falling edge events of a 4mhz input signal

Hi all, this is my first post. I am newbie with arduino.

First at all, I don't know really if what I want to do it's possible with my Arduino UNO or not, due speed limitations.

I'am trying to count the falling edge events that a 4Mhz input signal generates between a A-B range. The start and end of this range is triggered by a rising edge of another signal.

I have attach a image captured from my logic analyzer and shows what I want to count.

For counting I'am using ISR (avr code) interrupts with falling edge event activated but I have no success. I not able to count more than 1600 falling edge events into the A-B range and it should be 23040 in total.

This is my code (very simple):

int vsyncpin = 2;  // 60hz signal
int signalpin = 3;  // 4Mhz signal

volatile long signal_counts = 0;

void setup() {

  Serial.begin(1000000);
  cli();//stop interrupts  

  DDRD = B11110010; // arduino pins 2,3 are inputs

  PORTD = B00000000;

  pinMode(vsyncpin, INPUT);  
  EICRA |= (1 << ISC00);    // set INT0 to trigger RISING EDGE 
  EICRA |= (1 << ISC01);
  EIMSK |= (1 << INT0);     // Turns on INT0

  pinMode(signalpin, INPUT);  
  EICRA |= (0 << ISC10);    // set INT1 to trigger FALLING EDGE 
  EICRA |= (1 << ISC11);  
  EIMSK |= (1 << INT1);     // Turns off INT1

  sei();//allow interrupts
  
}

void loop() {
  // put your main code here, to run repeatedly:
}

ISR (INT0_vect)
{ 
  Serial.println(signal_counts); // each rising edge of vsync singal shows total counts in previous cicle and reset falling edge counter, first time will be 0 obviously
  signal_counts = 0;
}

ISR (INT1_vect)
{
  signal_counts++;
}

Any help is welcome.

Thanks in advance.

outputcount.JPG

4MHz will be to quick. That will just leave 16MHz / 4MHz = 4 ticks per interrupt. The overhead of jumping to the interrupt will already be more.

ISR (INT0_vect)
{
  Serial.println(signal_counts);

Rule-of-thumb: Don't do serial output in interrupt context.

Thanks for your responses.

septillion:
4MHz will be to quick. That will just leave 16MHz / 4MHz = 4 ticks per interrupt. The overhead of jumping to the interrupt will already be more.

I was thinking about that, but I am confused because I saw this project:

https://github.com/gillham/logic_analyzer // it's a logic analyzer with 4Mhz sampling rate

CtrlAltElite:

ISR (INT0_vect)

{
  Serial.println(signal_counts);



Rule-of-thumb: Don't do serial output in interrupt context.

jeje, it is a good advice but how could see the ouput without a serial print?

Regards

@ jotaduino

Let me understand your proposition; is it like this?

1. You have a 4 MHz free running clock.
2. You want to pass the signal of Step-1 through a gate which will be opened at Point-A, and it will be closed at Point-B. While the signal is passing through the gate, you wish to count the falling edges of the 4 MHz signal, which is essentially equal to number pulses going out through the gate. It is because, a signal pulse has only one falling edge.

3. What is the time difference between these two points (A, B)? Say, x.
4. You have said that the number of falling edges is expected to be 23040.
5. Based on the information of Step-4, the value of x is 23040x(1/4)x10-6 sec = 5760 us.

You'll probably need a faster processor. Maybe a STM32 may do the trick. Basic ones at 72MHz, more serious ones at 168MHz.

Oh! As said, NEVER use Serial inside an interrupt. And, in this context, use it as less as possible.

GolamMostafa:
@ jotaduino

Let me understand your proposition; is it like this?

1. You have a 4 MHz free running clock.
2. You want to pass the signal of Step-1 through a gate which will be opened at Point-A, and it will be closed at Point-B. While the signal is passing through the gate, you wish to count the falling edges of the 4 MHz signal, which is essentially equal to number pulses going out through the gate. It is because, a signal pulse has only one falling edge.

3. What is the time difference between these two points (A, B)? Say, x.
4. You have said that the number of falling edges is expected to be 23040.
5. Based on the information of Step-4, the value of x is 23040x(1/4)x10-6 sec = 5760 us.

Thank you for your reply.

The time difference between A and B is aprox 16.5ms (60Hz signal) you can see details in the image attached in my first post named falling_edges.JPG.

Regards

If the time difference between A and B is 16.5 ms, then the number of falling edges should be (for 4 MHz signal) 4x106x16.5x10-3 = 66000. Do you agree or not? How could it be 23040? Please explain.

Naguissa:
You'll probably need a faster processor. Maybe a STM32 may do the trick. Basic ones at 72MHz, more serious ones at 168MHz.

Oh! As said, NEVER use Serial inside an interrupt. And, in this context, use it as less as possible.

Thank you for your reply.

I could use the Serial.println in the main loop adding some logic to the code, but I thought that would be worse option.

Oh! As said, NEVER use Serial inside an interrupt. And, in this context, use it as less as possible.

Why are you so scared? Just re-enable the interrupt after arriving at the ISR.

GolamMostafa:
If the time difference between A and B is 16.5 ms, then the number of falling edges should be (for 4 MHz signal) 4x106x16.5x10-3 = 66000. Do you agree or not? How could it be 23040? Please explain.

As you can see in the attached Image there is a sleep time where there isn't clock signal. Exactly the gate time is 15.59ms, please, see image attached in this post.

GolamMostafa:
Why are you so scared? Just re-enable the interrupt after arriving at the ISR.

¿Really? and jump again on another interrupt if the Serial message isn't completed?

GolamMostafa:
Why are you so scared? Just re-enable the interrupt after arriving at the ISR.

Because he is trying to do a 4MHz sampling on a 16MHz microcontroller....

Also, it's just a rule of thumb for ISRs to leave as fast as possible.

And finally, there are microcontrollers where Serial uses interrupts, as said STM32, and will cause problems.

A much better alternative, as opener said, is to use Serial at loop. And again, use it as less as possible, when you're trying to score high speed sampling.

4MHz is only possible because they (in there own words) "hand padding loops with NOP instructions". Aka, they sample/poll the data (no interrupt) and time it with assembly code. It's fully based on a fixed number of loops so no external trigger/gate.

In theory you might be able to do the same but with the second channel as stop but even then, sampling 4MHz with 4MHz isn't sufficient. According to Nyquist you need at least twice that and that doesn't include phase shift, not 50% duty etc. I would say you need at least 16MHz sampling to have it correct.

Another way of doing it would be to use a counter to reduce the clock. If you insert a 8 stage counter you reduce the clock to 4MHz / 8 = 500kHz. That's still pretty fast but might be just enough to do with interrupts. With 16 stages you certainly have a slow enough clock. And if you connect all 8/16 stages (but only use stage 8/16 for the interrupt) you can determine the remainder as well so it doesn't even reduce the resolution.

Naguissa:
Because he is trying to do a 4MHz sampling on a 16MHz microcontroller....

Also, it's just a rule of thumb for ISRs to leave as fast as possible.

And finally, there are microcontrollers where Serial uses interrupts, as said STM32, and will cause problems.

A much better alternative, as opener said, is to use Serial at loop. And again, use it as less as possible, when you're trying to score high speed sampling.

In this case, if I not use Serial.print to output the results, how could I check the signal counter value?

I have an OLED 0.96" display ssd1306 compatible but I think that show there the results will consume more resources.

¿Really? and jump again on another interrupt if the Serial message isn't completed?

Just to allow @Naguissa (beecuse of the word -- NEVER --) enjoying the flavor of a nested interrupt. :slight_smile:

jotaduino:
In this case, if I not use Serial.print to output the results, how could I check the signal counter value?

Only show the result after you're done counting :wink:

jotaduino:
I have an OLED 0.96" display ssd1306 compatible but I think that show there the results will consume more resources.

Correct, I2C alone i already slower then Serial, not counting the extra overhead.

jotaduino:
In this case, if I not use Serial.print to output the results, how could I check the signal counter value?

I have an OLED 0.96" display ssd1306 compatible but I think that show there the results will consume more resources.

Well, if you need it, you can try. As said, one char by one, and it's the 1st place to look if any problem happens.

I think I would set char and a flag in interrupt and send it in loop:

volatile bool noNewFlag = true;
volatile char last;


void loop() {
    if (noNewFlag) {
        return;
    }
    Serial.write(last);
    noNewFlag = true;
}

// In the ISR:
last = NewValue;
noNewFlag = false;

If you loose data... you're out of luck.

Just to allow @Naguissa (beecuse of the word -- NEVER --) enjoying the flavor of a nested interrupt. :slight_smile:

:smiley:

It's just that if you say "try to avoid" people seems to understand "avoid but all my cases are special cases"...

I have improved the code but I am not able to get more than 1630-1700 fallind edge events almost the same value that the initial code. Really I don't know if there is some error in my idea or simply arduino uno with his 16Mhz can't sample a 4Mhz signal.

int vsyncpin = 2;  // 60hz signal
int signalpin = 3;  // 4Mhz signal

volatile long signal_counts = 0;

volatile bool show = false;

void setup() {

  Serial.begin(1000000);
  cli();//stop interrupts  

  DDRD = B11110010; // arduino pins 2,3 are inputs

  PORTD = B00000000;

  EICRA |= (1 << ISC00);    // set INT0 to trigger RISING EDGE 
  EICRA |= (1 << ISC01);
  EIMSK |= (1 << INT0);     // Turns on INT0

  EICRA |= (0 << ISC10);    // set INT1 to trigger FALLING EDGE 
  EICRA |= (1 << ISC11);  
  EIMSK |= (1 << INT1);     // Turns off INT1
 
  sei();//allow interrupts
  
}

void loop() {
  if (show){
    Serial.println(signal_counts);
    show = false;
    signal_counts = 0;
  }
}

ISR (INT0_vect)
{      
  if (!show){
    //TIMSK1 |= (1 << OCIE1A);
    show = true;
  }
}

ISR (INT1_vect)
{
  signal_counts++;
}

I have improved the code but I am not able to get more than 1630-1700 fallind edge events almost the same value that the initial code. Really I don't know if there is some error in my idea or simply arduino uno with his 16Mhz can't sample a 4Mhz signal.

If you would be eager to answer my questions of Post#4 and 7 honestly, I would certainly prescribe an alternate way of counting (without interrupt) the falling edges of your 4 MHz signal in the window of 16.6 ms.