Arduino output pulse unable to synchronize with an encoder

I'm trying to output a pulse after receiving the rising edge of an external trigger (from an encoder). There is a time interval of several microseconds between the pulse and the trigger,which could be changed through the program. But we found the pulse is jittering, for about 5us.
For example, most of time, the time interval between the pulse and the trigger is 8us, but frequently, it jitters from 8 to 14us.

If we inspect with OSC, we could see the pulse jitters back accidentally without obviously period and
it could last 5 us at most.

The peripheral hardware is simple. There is a signal generator hooked up to the external interrupt of the Arduino Uno, and we observed the output pin with an oscilloscope.
The yellow line represents the trigger pulse, and the blue line represents the output pulse.The oscilloscope is triggered by the yellow line.
The following pictures show the jittering of the output pulse .

The program is as follows:

  • int trigger = 4;

void setup() {
pinMode(trigger, OUTPUT);
attachInterrupt(1, blink, RISING);//trigger by TTL rising.
}

void loop() {
}

void blink()
{
digitalWrite(trigger,HIGH); // output input trigger
delayMicroseconds(100); // High TTL level laststriggers for 100us
digitalWrite(trigger,LOW);
}

What I have tried are these:
1,Use another signal generator or another Arduino board. The pulse jitter remains.
2,Alter the trigger frequence.The pulse jitter appears if only the frequence higher than 40Hz.
So,I myself think it doesn't matter with the signal generator.

3,Modify the program to achieve the similar function through capturing the HIGH level of the trigger rather than its rising edge. The pulse jitter remains, while it appears not so frequently as before.
4,Add noInterrupts() and interrupts() to avoid ISR being interrupted accidently.The pulse jitter remains.

We know that the interrupt starts only after the current running instruction finishes, the clock cycles of the different instrcutions vary a lot, which may cause the output pluse jitter a little bit. But this variation is much less than 5us.

I was frustrated.Is it's the residual accumulation between crystal oscillator period and the external trigger's period that leads to the pulse jitter? But,could it reach a 5us long jitter?

Please help me!

pictures are in the attachment following

digitalWrite() is a slow function. It may be worth using port manipulation which allows the pins to change very much faster.

I don't like the idea of having a delay in an ISR. Does delayMicroseconds() work while interrupts are disabled ?

If this was my project I would use the ISR to switch on the LED and record the time and then use the code in loop() to turn it off when the interval expires.

Or, if more precise timing is required, use one of the hardware Timers to deal with the interval. Your trigger ISR could turn on the LED and start the Timer. The Timer would then trigger a different interrupt to switch off the LED.

...R

Robin2:
digitalWrite() is a slow function. It may be worth using port manipulation which allows the pins to change very much faster.

I don't like the idea of having a delay in an ISR. Does delayMicroseconds() work while interrupts are disabled ?

If this was my project I would use the ISR to switch on the LED and record the time and then use the code in loop() to turn it off when the interval expires.

Or, if more precise timing is required, use one of the hardware Timers to deal with the interval. Your trigger ISR could turn on the LED and start the Timer. The Timer would then trigger a different interrupt to switch off the LED.

...R

Thanks! And I tried following your advises. The results are These:

It do change the pins much faster,if I use port manipulation. But the output pulse jitter remains.

delayMicroseconds() works very well when interrupts are disabled. And delayMicroseconds() no longer disables interrupts.
My testing program is like belows. It blinks well.

int trigger = 4;
void setup() {
pinMode(trigger, OUTPUT);
}

void loop() {
noInterrupts();
digitalWrite(trigger,HIGH);
delayMicroseconds(100);
digitalWrite(trigger,LOW);
delayMicroseconds(100);
}

If I use ISR to switch on the LED only and record the time and then use the code in loop() to turn it off when the interval expires.
The output pulse jitter remains. And also the precision is not enough for me because micros() has a resolution of four microseconds on 16 MHz Arduino boards.
The testing program is as follows:

unsigned long lasttime;

void setup() {
DDRD = DDRD | B00010000; //set dp4 OUTPUT
attachInterrupt(1, blink, RISING);//trigger by TTL rising.
}

void loop() {
if((micros() - lasttime) > 100) //HIGH for 100us
{
PORTD = PORTD & B11101111 ;
}

}

void blink()
{
PORTD = PORTD | B00010000 ; //set dp4 HIGH
lasttime = micros();
}

osler:
My testing program is like belows. It blinks well.

If I use ISR to switch on the LED only and record the time and then use the code in loop() to turn it off when the interval expires.
The output pulse jitter remains. And also the precision is not enough for me because micros() has a resolution of four microseconds on 16 MHz Arduino boards.

First - do us a favour and use the normal code tags for your code - use the code button </>

so your code looks like this

I don't see the relationship between the first piece of code, which detects nothing and the second piece of code.

In the first piece of code there is a noInterrupts() without a corresponding interrupts(). The Arduino needs interrupts to do stuff in the background. And I thought you had switched to using port manipulation.

As I said in Reply #2 if the resolution of micros() is not sufficient you will need to use one of the Hardware Timers.

Can you make a simple pencil drawing (not a 'scope screen capture) that illustrates the jitter problem more clearly and post a photo of the drawing.

It would also be helpful if you can describe all the stuff the finished program will have to do. If it's only job is to make this pulse it may allow a simpler solution.

...R

Hi,
What is your application, is all you want a pulse that occurs on the rising edge of another?
Is there any reason why you cannot do it with hardware, such as a 4000 series digital monostable?

Tom... :slight_smile:

TomGeorge:
Hi,
What is your application, is all you want a pulse that occurs on the rising edge of another?
Is there any reason why you cannot do it with hardware, such as a 4000 series digital monostable?

Tom... :slight_smile:

There is a time interval of several microseconds between the pulse and the trigger,which could be changed through the program.
And in the last, there will be several pulses with different delay times.

Robin2:
First - do us a favour and use the normal code tags for your code - use the code button </>

so your code looks like this

I don't see the relationship between the first piece of code, which detects nothing and the second piece of code.

In the first piece of code there is a noInterrupts() without a corresponding interrupts(). The Arduino needs interrupts to do stuff in the background. And I thought you had switched to using port manipulation.

As I said in Reply #2 if the resolution of micros() is not sufficient you will need to use one of the Hardware Timers.

Can you make a simple pencil drawing (not a 'scope screen capture) that illustrates the jitter problem more clearly and post a photo of the drawing.

It would also be helpful if you can describe all the stuff the finished program will have to do. If it's only job is to make this pulse it may allow a simpler solution.

...R

Sorry for not so familar with the operation.

The first piece of code is used to answer your question " Does delayMicroseconds() work while interrupts are disabled ?". And I was also surprised that it runs normally without interrupts() in this code.Though I know there should be a interrupts(), but it did run well.

The program is trying to output a pulse after receiving the rising edge of an external trigger (from an encoder). There is a time interval of several microseconds between the pulse and the trigger,which could be changed through the program. But we found the pulse is jittering, for about 5us.

A simple pencil drawing showing the jitter problem is in the attachment. Most times,the output pulse is stability. But sometimes, it jitters about 2 to 5 us, without obviously period.

osler:
It do change the pins much faster,if I use port manipulation. But the output pulse jitter remains.

Any jitter you observe is caused by the Timer0 interrupts which will fire about once per millisecond and which runs for about 4 microseconds then.

If you want to avoid jitter, you better disable Timer0 and avoid all the comfort functions that are derived from that: millis(), micros(), delay() and delayMicroseconds().

After disabling Timer0 use '_delay_us()' out of the AVR LIBC in <util/delay.h> instead!

Hi,

And in the last, there will be several pulses with different delay times

Use more than 1 hardware delay.
Do you need to adjust the delay, or is it fixed.
How many pulses are you going to be delaying and will they all be at the same frequency?

Tom.... :slight_smile:

TomGeorge:
Hi,

Use more than 1 hardware delay.
Do you need to adjust the delay, or is it fixed.
How many pulses are you going to be delaying and will they all be at the same frequency?

Tom.... :slight_smile:

The delaytime need to be adjusted. About 6 pulse will be given. They have a same frequency, But the delaytimes are different.

jurs:
Any jitter you observe is caused by the Timer0 interrupts which will fire about once per millisecond and which runs for about 4 microseconds then.

If you want to avoid jitter, you better disable Timer0 and avoid all the comfort functions that are derived from that: millis(), micros(), delay() and delayMicroseconds().

After disabling Timer0 use '_delay_us()' out of the AVR LIBC in <util/delay.h> instead!

Thanks a lot. I will try in your advice, and I will tell you the result later. I think what you said maybe is the reason.

jurs:
Any jitter you observe is caused by the Timer0 interrupts which will fire about once per millisecond and which runs for about 4 microseconds then.

If you want to avoid jitter, you better disable Timer0 and avoid all the comfort functions that are derived from that: millis(), micros(), delay() and delayMicroseconds().

After disabling Timer0 use '_delay_us()' out of the AVR LIBC in <util/delay.h> instead!

Thanks for your proposal! I have solved this problem by adding "TIMSK0 = TIMSK0 & B11111110;" to disable Timer0. The 5us pulse jitter dissappeard.