How to prevent jittering

Hey guys

I'm working on a project and I have a problem: I call an interrupt every time my arduino nano senses a peak voltage on pin D2. This interrupt is responsible to store the exact time(using millis()) it was called into an array.

Then, in my loop, I do a logic to generate a delayed pulse using the idea of millis() instead of delay(). However, I noticed via oscilloscope that this pulse is jittering so much, and for my application that's not good.

Any solutions for this issue?

Thanks

Any solutions for this issue?

Yep. Fix your code. Since you didn't post your code here, you can'r reasonably expect help here.

Also, how much is the jitter (microseconds) and what is your target?

The jitter is around 4ms and I need to generate pulses of 50us width , but steady... at the moment it keeps shifting around and that's bad for my application, because this pulse will be triggering another circuit.

It seems unlikely that you'll receive significant help without first posting your code.

Sounds like your sketch might have a mistake in Line 57.

Use CTRL T to format your code.
Attach your complete sketch between code tags
[code]Paste your sketch here[/code]

Show us a good schematic & image of your circuit.
Posting images:

Sender

#include <SoftwareSerial.h>
SoftwareSerial mySerial (8,9); //rx,tx


String dataPy;
int inPin = 2;
int i;
int dataIn;
char str[4];
volatile unsigned long timeout[4];
volatile int idx = 0;
volatile unsigned long actTime; 

void setup() {
  
 pinMode(inPin,INPUT); // set pinD2 up to input
 DDRD = 1 << DDD7; // set pinD7 up to output
 Serial.begin(9600); 
 mySerial.begin(9600);
 attachInterrupt(digitalPinToInterrupt(inPin),peakID,RISING); // declarying the interrupt to be triggered

}


void loop() {

    if(Serial.available()>0){ //Serial communication 
       dataPy = Serial.readString(); // read the string inside the buffer
       dataIn = atoi(dataPy.c_str()); // convert income string to char and then, to int
       mySerial.write(itoa(dataIn,str,10)); //convert int to char array in a decimal base and sends to ard2
      }

      actTime = millis(); // actTime stores the amount of time since the program started
       
      for(i=0; i<4; i=i+1){
          if(actTime - timeout[i] == dataIn){
          timeout[i]=0; //guarantee that the pulse is generated just one time
          PORTD = 1 << PD7; // HIGH
          delayMicroseconds(50); // pulse width
          PORTD = 0 << PD7; // LOW
          delayMicroseconds(50);
           
          }
        
      }
    
}

 
void peakID(){ // triggered interrupt

   timeout[idx] = millis(); // assign the time when the interrupt is called to an array
   
   if (idx == 3){ // pointer setup
    idx = 0;
    }
   else{
    idx = idx+1;
   }
   
}

Receiver

#include <SoftwareSerial.h>
SoftwareSerial mySerial (8,9); //rx,tx


String dataArd;
int inPin = 2;
int i;
int dataIn;
volatile unsigned long timeout[4];
volatile int idx = 0;
volatile unsigned long actTime; 

void setup() {
  
 pinMode(inPin,INPUT); // set pinD2 up to input
 DDRD = 1 << DDD7; // set pinD7 up to output
 mySerial.begin(9600);
 attachInterrupt(digitalPinToInterrupt(inPin),peakID,RISING); // declarying the interrupt to be triggered

}


void loop() {

      if(mySerial.available()>0){
          dataArd = mySerial.readString(); // reads the income string from ard1
          dataIn = atoi(dataArd.c_str()); // convert char array to int and assign the result to dataIn 
      }
      
      actTime = millis(); // actTime stores the amount of time since the program started
       
      for(i=0; i<4; i=i+1){
        if(actTime - timeout[i] == dataIn){
          timeout[i]=0; //guarantee that the pulse is generated just one time
          PORTD = 1 << PD7; // HIGH
          delayMicroseconds(50); // pulse width
          PORTD = 0 << PD7; // LOW
          delayMicroseconds(50);
           
          }
        
      }
    
}

 
void peakID(){ // triggered interrupt

   timeout[idx] = millis(); // assign the time when the interrupt is called to an array
   
   if (idx == 3){ // pointer setup
    idx = 0;
    }
   else{
    idx = idx+1;
   }
   

}

I send a value from Python(around 200ms) using serial USB to one of my Arduinos. Then, this value is transmitted from one to the other via TX RX. Before implementing the communication I already had problems with jittering.

Crespo94: The jitter is around 4ms and I need to generate pulses of 50us width , but steady... at the moment it keeps shifting around and that's bad for my application, because this pulse will be triggering another circuit.

hmmm... I cannot say about your code, but for 50usec you better take a look on the following

https://www.youtube.com/watch?v=648Tx5N9Zoc

Thanks for the reply! I watched the video, tried to implement the idea on my code, but nothing new has occurred yet

9600 baud? No wonder... Try 115200

I have just tried by 115200 bps and it is still jittering crazily.

Can you provide a diagram of all your hardware and how it is hooked up?

Are you sure that the signal used for interrupt is "clean" (no jitter, fast rise/fall times, no ringing, clear recognizable levels for HIGH/LOW...)?

Update: I noticed that by 115200 the jittering process still occurs, but the deviation in comparison to the exact value that I send via USB and TXRX is ok.

But I also noticed that values larger than 240 doesnt affect my Arduinos. It seems like they dont flow through usb or txRx.

The code in Python is simple as that:

import serial
import time as t

   
serialCom = serial.Serial(port = 'COM9', baudrate = 115200, bytesize = serial.EIGHTBITS, parity=serial.PARITY_NONE, timeout=1) #initializing serialCom
t.sleep(2)

tau = 240 #desired delay in ms
serialCom.write(str(tau).encode('ascii')) #write on serialCom
#serialCom.close()
[\code]

The readString() function is giving you up to1000ms of dead time.

if(actTime - timeout[i] == dataIn){

Don't use == for millis. The slower Arduinos don't always increment by 1ms. Sometimes* they skip one.

The timeout[] values have 32 bits. An 8-bit Arduino takes 4 instructions to read those out of the memory. An interrupt can occur in between those instructions and scramble the value. Then you do a bunch of other instructions and then write to the value. An interrupt can occur there too. That might be a bigger problem for your program.

Any time you read or write to a volatile variable longer than your processor's word size, wrap it in noInterrupts[]; interrupts();

While we are looking at variable sizes, why do you store the numbers 0-3 in a 16-bit int? Your interrupt will be much more efficient if you use a byte or uint8_t for idx.

  • "sometimes" is about one in a thousand, which seems unlikely until you remember that there is 1000 milliseconds every second.

First, expanding on @MorganS’s point, I’d use micros() for all timing.

Second, I’d abandon entirely the technique you’re trying to use and move to a method using timer interrupts. I haven’t worked out all the details in my mind yet, but it would involve storing the times of future output events (Rising or Falling) in two FIFOs every time you get an interrupt due to your input signal. The time of the next event would determine when a timer interrupt should occur. When that timer interrupts occurs, you’d change the output, remove the event from the FIFO, and set up the next timer interrupt based on the next FIFO event in the future (if there is one). You’d have to handle the special case of an empty FIFO to start things off or if your input repetition rate is slow relative to your delay time.

Finally, I’d get all this working on a single board with a fixed delay before moving on to variable delays read from Serial or communications with multiple boards.

Thanks for the reply MorganS. I have some questions regarding what you said:

1) == millis() issue: instead of using equals, > would be the solution or is there another possibility to compare those values in order to obtain the delayed pulse?

2) When you say: " wrap it in noInterrupts() and interrupts()" ... would this block inside loop() or inside my interrupt function be placed?

3) variable size: do you think it's a problem to store values from millis() into an array as in timeOut[]? If not, by changing idx to byte or uint_8 , would it better for my code? That's not 100% clear to me.

Thank you for the reply gfvalvo! I will look for this FIFOs and see how it works.

Crespo94: Thank you for the reply gfvalvo! I will look for this FIFOs and see how it works.

The key to my suggested technique is not the FIFO, it's the use of a hardware counter/timer to generate more precisely-controlled timing. The reason I mentioned using a FIFO is because you used one in your original code. I assumed it was because the period of you input pulses could be shorter than the value of required delay. Hence, events need to be queued up.