I am using the ATMega32u4 to generate multiple pulses at 2.5 kHz. I am using Timer 3, which is a 16-bit timer and using a prescaler of 1, so I have a 0.0625uS resolution. I want to generate pulses with pretty high accuracy and consistency. I have my previous posthere, which gave me accuracy. But when I look at the pulse with my oscilloscope it has some jitter.Youtube Video of Jitter.
My final goal is to create a pulse on multiple different pins in this configuration.
What I amassuming is that the reason there is jitter is that there are other interrupts going on in the background, that could be shifting when the pulse stops and starts by a few microseconds. Looking through the datasheet, I found this, which seems to show interrupt priority.
It seems that my TIMER3 COMPA and COMPB are very low down the list of priorities, is there a way to change this priority list? Or is there something else that is causing the jitter?
I have posted my code below:
#define pin2 12#define pin3 6#define pin4 8#define REFRESH 6400int PULSEIndex;class Pulse { public: int pulseLength; void Begin(byte GPIO_PIN) { pinMode(GPIO_PIN, OUTPUT); } void writeMicro(double pulse) { pulseLength = (pulse * 16); }};Pulse PULSE1;Pulse PULSE2;Pulse PULSE3;Pulse PULSE4;void setup() { PULSE1.Begin(pin1); PULSE2.Begin(pin2); PULSE3.Begin(pin3); PULSE4.Begin(pin4); // Reset Timer 3 Control Register to 0 TCCR3A = 0; TCCR3B = 0; // Set CTC Mode TCCR3B &= ~(1 << WGM33); //0 TCCR3B |= (1 << WGM32); //1 // Set prescaler to 1 TCCR3B &= ~(1 << CS32); //0 TCCR3B &= ~(1 << CS31); //0 TCCR3B |= (1 << CS30); //1 //Reset Timer 3 and set compare value TCNT3 = 0; // Enable Timer 3 compare interrupt A and B TIMSK3 |= (1 << OCIE3B); TIMSK3 |= (1 << OCIE3A); //Enable global interrupts sei(); //Set Refresh Rate OCR3A = REFRESH; OCR3B = 1000;}void loop() { PULSE1.writeMicro(40); PULSE2.writeMicro(40); PULSE3.writeMicro(40); PULSE4.writeMicro(40); delay(2);}ISR(TIMER3_COMPA_vect) { digitalWrite(pin1, HIGH); OCR3B = PULSE1.pulseLength;}ISR(TIMER3_COMPB_vect) { if (PULSEIndex == 1) { digitalWrite(pin1, LOW); digitalWrite(pin2, HIGH); OCR3B += PULSE2.pulseLength; } if (PULSEIndex == 2) { digitalWrite(pin2, LOW); digitalWrite(pin3, HIGH); OCR3B += PULSE3.pulseLength; } if (PULSEIndex == 3) { digitalWrite(pin3, LOW); digitalWrite(pin4, HIGH); OCR3B += PULSE4.pulseLength; } if (PULSEIndex == 4) { digitalWrite(pin4, LOW); } PULSEIndex++; if (PULSEIndex > 4) PULSEIndex = 1;} ```- Fist try to access pins directly. The
digitalWriteis extremely slow, and at least for the first pulse it's nodigitalWrite(pin4, LOW);, so there is few microseconds jitter. Just like that. Maybe consider MCU with DMAKIIV– KIIV2020-05-16 05:42:20 +00:00CommentedMay 16, 2020 at 5:42 - 2I'm not 100% sure, but I think the interrupt priorities are fixed in hardware.the busybee– the busybee2020-05-16 06:24:07 +00:00CommentedMay 16, 2020 at 6:24
1 Answer1
What I amassuming is that the reason there is jitter is that there are other interrupts going on in the background
This seems like a reasonable assumption. Since you are not doing serialcommunication, the Timer 0 interrupt is likely the only one triggeringin the background. You can disable it with:
TIMSK0 = 0;but then all the Arduino timing functions will stop working. You willhave to#include <util/delay.h> and replacedelay() with_delay_ms(). Note that this avr-libc function only works withcompile-time constant delays. On the other hand, it is cycle-accurateand accepts floating point delays.
is there a way to change this priority list?
There is not, and even if this was possible, it would not be thatuseful. Interrupts in the Arduino are not interruptible: if alow-priority interrupt is running when a high-priority one triggers, thehigh-priority interrupt has to wait for the currently running one toterminate. Priorities are only relevant when the processor is about toserve an interrupt request but has to decide which one, among severalpending requests, it will serve first.
Now, a small remark about this:
void loop() { PULSE1.writeMicro(40); PULSE2.writeMicro(40); PULSE3.writeMicro(40); PULSE4.writeMicro(40); delay(2);}There is no point in rewriting those values over and over again. If youplan to change the code in order to make those widths non-constant, thenyou have to take care to:
- make the
pulseLengthproperties (or the wholePulseobjects)volatile - within
writeMicro(), disable interrupts while changingpulseLength.
Explore related questions
See similar questions with these tags.
