DUE PWM Jitter

I’ve been developing code to create two out of phase triangle PWM signals. I’ve already filtered the signal output with a highpass LC filter. The signals are required to feed two IBT-2 H-Bridge modules. Each H-Bridge is connected with its own filters and coils. As you can see from the code, I need higher frequency PWM signals to better filtering. I can not use DAC signals. I need direct PWM control on the H-Bridges modules for efficiency. I also need the PWM signals to smoothly change in frequency, hence the analogread(0). As you can see, I’ve added a trigger signal, just for easily viewing the PWM signals on a scope.

My problem is…I continue to get unpredictable jitter in the PWM signals. See the attached image. There is no pattern to the jitter. Very random. I’ve tried multiple ways to eliminate the jitter. I recently placed while loops using micros() instead of delays, thinking this was the problem and still get the issue. I’ve tried to read and understand the register data on the datasheet and still not getting great results. I’m also using the DUE Arduino board, hopefully this helps.

Is there a way to remove this jitter signal?

typedef struct {
    Tc *pTC;        // TC0, TC1, or TC2
    byte channel;   // 0-2
    byte output;    // 0 = A, 1 = B
}  

tTimerInfo;

tTimerInfo timerLookup [] =
{
  {NULL,0,0}, // 0
  {NULL,0,0}, // 0
  {TC0,0,0},  // pin 2 = TIOA0
  {TC2,1,0},  // pin 3 = TIOA7
  {TC2,0,1},  // pin 4 = TIOB6
};

uint32_t setupTimerPwm (byte pin, uint32_t frequency, unsigned dutyCycle)
{
  uint32_t count = VARIANT_MCK/2/frequency;
  tTimerInfo *pTimer = &timerLookup[pin];

  {
    TC_SetRC (TC2, 0, count);
    if (pTimer->output == 0)
       TC_SetRA (TC2, 0, count * dutyCycle / 4095);
    else
       TC_SetRB (TC2, 0, count * dutyCycle / 4095);

    return count;
  }

}

int tri[] = {
0x2d, 0x5a, 0x88, 0xb5, 0xe2, 0x10f,0x13d,0x16a,0x197,0x1c4,
0x1f2,0x21f,0x24c,0x279,0x2a7,0x2d4,0x301,0x32e,0x35c,0x389,
0x3b6,0x3e3,0x411,0x43e,0x46b,0x498,0x4c6,0x4f3,0x520,0x54d,
0x57b,0x5a8,0x5d5,0x602,0x630,0x65d,0x68a,0x6b7,0x6e5,0x712,
0x73f,0x76c,0x79a,0x7c7,0x7f4,0x821,0x84f,0x87c,0x8a9,0x8d6,
0x904,0x931,0x95e,0x98b,0x9b9,0x9e6,0xa13,0xa40,0xa6e,0xa9b,
0xac8,0xaf5,0xb23,0xb50,0xb7d,0xbaa,0xbd8,0xc05,0xc32,0xc5f,
0xc8d,0xcba,0xce7,0xd14,0xd42,0xd6f,0xd9c,0xdc9,0xdf7,0xe24,
0xe51,0xe7e,0xeac,0xed9,0xf06,0xf33,0xf61,0xf8e,0xfbb,0xfe8,
0xfff};

int atri[] = {
0xfff,0xfe8,0xfbb,0xf8e,0xf61,0xf33,0xf06,0xed9,0xeac,0xe7e,
0xe51,0xe24,0xdf7,0xdc9,0xd9c,0xd6f,0xd42,0xd14,0xce7,0xcba,
0xc8d,0xc5f,0xc32,0xc05,0xbd8,0xbaa,0xb7d,0xb50,0xb23,0xaf5,
0xac8,0xa9b,0xa6e,0xa40,0xa13,0x9e6,0x9b9,0x98b,0x95e,0x931,
0x904,0x8d6,0x8a9,0x87c,0x84f,0x821,0x7f4,0x7c7,0x79a,0x76c,
0x73f,0x712,0x6e5,0x6b7,0x68a,0x65d,0x630,0x602,0x5d5,0x5a8,
0x57b,0x54d,0x520,0x4f3,0x4c6,0x498,0x46b,0x43e,0x411,0x3e3,
0x3b6,0x389,0x35c,0x32e,0x301,0x2d4,0x2a7,0x279,0x24c,0x21f,
0x1f2,0x1c4,0x197,0x16a,0x13d,0x10f,0xe2 ,0xb5 ,0x88 ,0x5a ,
0x2d};

const int sPWMArrayValues = 91;           // sPWM table array value
const int freq = 15000;                   // sPWM frequency
const int trig = 18;                      // Trigger

unsigned long time_now = 0;

void setup() {
  analogWrite (4, 1);
  analogWrite (5, 1);
  pinMode(trig, OUTPUT);
  }

void loop() {
  
 int val = analogRead(0);                 //ADC
  val = map(val, 0, 1023, 1, 300);        //store delay value and map 
  
  digitalWrite (trig, HIGH);              //using this as a trigger to read both PWM signals on scope
  
  TC_Start (TC2,0);
  for(int i(0); i != sPWMArrayValues; i++){
    time_now = micros();
    while(micros() < time_now + val);{}
    setupTimerPwm (4, freq, tri[i]); 
    setupTimerPwm (5, freq, atri[i]);
    }

  digitalWrite (trig, LOW);
  
  for(int i(0); i != sPWMArrayValues; i++){
    time_now = micros();
    while(micros() < time_now + val);{}
    setupTimerPwm (4, freq, atri[i]); 
    setupTimerPwm (5, freq, tri[i]);
    } 

}

To avoid jitter data transfer has to be done by hardware, DMA. I see SAM3X has PDC (DMA helper) channel to PWM, there is no DMA to Timer, so all you have to do is link data ->dma ->PWM. There may be some library, try key words in google

There are numerous PWM example sketches in the DUE sub forum to output 2 weveforms 90° out of phase, like these ones (reply #85 and #87):

For your H bridge, you may need some dead time between the 2 waveforms.

ard_newbie:
you may need some dead time between the 2 waveforms.

Thanks, your suggestion at looking at the dead time between the two waveforms seems to be the issue.
After further investigation, I can see clearly that the jitter is happening on both waveforms at the same time when the error happens. The error is sporadic but does happen to both waveforms at the same time. I hope this is the issue.

Do you have any suggestions on how to implements dead time within my code shown above? Both PWM waveforms are using the same channel but two different outputs. They are synced together. I'm fine with several microseconds of dead time between the two waveforms.

Thanks.

Sorry, I know for sure it's not the dead time that is needed. I've commented one waveform out and singled out one side only and it did not eliminate the jitter for just one waveform.

As for PDC DMA, this is a whole new ball game of tricks to speed up memory access. I have not found any library to help with DMA. Help would be appreciated. Unfortunately, this area of modification if not clear to me.

I'd like to keep the current code with modification if possible.

Could it be that this math within the interrupt is taking too long?

count * dutyCycle / 4095

Thanks.