jitter-free sub-us precision in waveform generation

Hello All,

Arduino Uno newbie here.

My goal is the following:

  • receive a (8KHz) digital square wave trigger on the arduino
  • generate a square waveform (by specifying a delay and a duration) initiated by the trigger
  • the waveform should have sub-us jitter (ideally as small as possible) pulse to pulse

Here is the code I currently have:

float testDel = 10; // us
float testDur = 20; // us

void setup() {
DDRD |= B11111100; // digital pins 7,6,5,4,3,2 as output, ignores pins 0,1
DDRB = B00000000; // digital pins -,-,13,12,11,10,9,8 as input
}

void loop() {
noInterrupts();
if (PINB & B00010000) { // If receiving trigger on pin 12
delayMicroseconds(testDel); // wait testDel us
PORTD |= B00000100; // pin2 high
delayMicroseconds(testDur); // wait testDur us
PORTD &= B11111011; // pin2 low
}
}

I have had some success in reducing the jitter by using "nointerrupts()" in my void loop.

Is there any cost to doing things this way? Or maybe a better/more elegant way to do this?

I have read things that suggest I might be able to reduce the timing jitter potentially more effectively by accessing the system clock directly. I have no experience doing this yet and am currently reading more about it, but if anyone on the forum has any suggestions for other ways to do this potentially even better I would be curious to hear your suggestions.

Thanks,
mundu

You can use one of the timers to generate a pulse train with essentially no jitter. Tutorial here.

Read this:

Sub µs i.e. into nano seconds on a micro using code becomes difficult.

Look into using hardware timers.

What school work is this for?

float testDel = 10;    That's not helping your assignment

jremington:
You can use one of the timers to generate a pulse train with essentially no jitter. Tutorial here.

Thanks very much I am looking into this.

It seems a timer could be set up to begin counting after a digital input pin goes from low to high (eg. 12), and then raise an output pin (eg. 2) from low to high after a timer gets to a certain value? -- If I understand correctly, this could generate a (very precise sub-us) "delay".

Then... a timer could be set up to begin counting after the digital output pin (2) goes from low to high, and set digital output pin 2 to low once the timer gets to a specific value? -- This could generate the (very precise sub-us) "duration" of the pulse.

Using noInterrupts(); I guess this should be the most jitter-free signal an arduino can produce on a sub-us timescale?

I am also looking into using delay_x which I found on another forum post
https://forum.arduino.cc/index.php?topic=116725.0

Ok, so I have been reading quite a bit from your references and have now found out how to make:

(1) - a jitter-free square waveform using hardware timers (this is the only signal that seems to be truly "jitter-free" that I have been able to make) - adapted from gammon

(Now, learn how to use Code tags please!)

** **/////////////////////////////////////////////////////////////////////////////////////////////////////////////////** **

#include <avr/sleep.h>

#include <util/delay.h>


double inputDel = 80; //us

double inputDur = 40; //us



ISR (TIMER1_COMPA_vect)

 {

   _delay_us(inputDel);          // delay before rise time

   PORTB |= B00010000;                

   _delay_us(inputDur);          // duration of high time

   PORTB = B00000000;

 }  

 

void setup ()

 {

 DDRB |= B11111111;                      // digital pins -,-,13,12,11,10,9,8 as output

 DDRD = B00000000;                       // digital pins 7,6,5,4,3,2,1,0 as input



 // stop timer 0

 TCCR0A = 0;

 TCCR0B = 0;

 

 // stop timer 1

 TCCR1A = 0;

 TCCR1B = 0;

 

 TCCR1B = bit (WGM12) |  // CTC

          bit (CS10);    // prescaler of 1



 // 1e9 / 22050 / 62.5 = 725.6 - round down, then subtract 1

 OCR1A = 800;

 TIMSK1 = bit (OCIE1A);  // interrupt on compare A

 

 set_sleep_mode (SLEEP_MODE_IDLE);  



 }  // end of setup



void loop ()

 {

 sleep_mode ();

 }  // end of loop

** **/////////////////////////////////////////////////////////////////////////////////////////////////////////////////** **

(2) - a CLOSE to jitter-free signal using external interrupts. This is extremely close to what I need, but I really need the "jitter free" signal as in the one generated by hardware timers in the previous example.

[b]/////////////////////////////////////////////////////////////////////////////////////////////////////////////////[/b]
#include <util/delay.h>

#include <avr/sleep.h>



const byte interruptPin = 2;

const byte outputPin = 12;

double testDel = 10;



void trigger () {

/////////////////////////////////////////////////////////////////////////////

//    PORTB |= B00010000;                 // show when signal is recieved

//    PORTB &= B11101111;

/////////////////////////////////////////////////////////////////////////////

   _delay_us(testDel);

   PORTB |= B00010000;                // pin12 high

   _delay_us(testDel);

   PORTB = B00000000;

}



void setup() {

   DDRB |= B11111111;                      // digital pins -,-,13,12,11,10,9,8 as output

   DDRD = B00000000;                       // digital pins 7,6,5,4,3,2,1,0 as input

   attachInterrupt(digitalPinToInterrupt(interruptPin),trigger,RISING);

   set_sleep_mode (SLEEP_MODE_IDLE);  

}



void loop() {

 sleep_mode ();

}

[b]/////////////////////////////////////////////////////////////////////////////////////////////////////////////////[/b]

I am reaching out for your expertise for help in getting the rest of the way.
I need to either:
(1) - adapt the hardware timer version to initiate on an external trigger (ie. pin 2 change) -- I am relatively new to hardware timers, so I'm not sure how to do this one.
-or-
(2) - try to remove the residual jitter from the interrupt version (I don't know where it's coming from now).
Thanks,
mundu

It appears the additional timing jitter in (2) was coming from timer interrupts.

by setting TIMSK0, TIMSK1, TIMSK2 all equal to zero in void setup(), the jitter was completely removed (now any jitter I see is on the order of a clock cycle), so I suppose it must have been due to timer interrupts.

If anyone else ever needs to do this, all you need to do is to modify the void setup() in the code (2) that is posted in my previous post, and add:

TIMSK0 = 0;
TIMSK1 = 0;
TIMSK2 = 0;

and it should remove any residual jitter you are seeing in your custom waveform.

Fair warning, turning off Timer0 interrupt breaks millis().