Phase shift PWM in Arduino DUE using Timer counter

Hello everyone,
I am trying to implment 3 SPWM signals with PWM shifted by 60 degree and 120 degrees ( shifted carrier not the sinusiodal signal). So , I depend on the 3 channels of the timer counter 2 to do this and channel zero of TC0 for time delay. The code below explains what I have done. The main problem is that the output signals are not stable and the sifted signals works for about 3 periods then keep high for 2 periods.
Are there any better whay to generate those three signals ??

int temp;
#define SinDivisions (5000) // 5000 pulse for each one period of output sine wave, switching frequency/sine wave fequency (250KHz/50 Hz)=5000
static unsigned int lookUpch1[SinDivisions];
int period=168;
int fsw=250; //250 [KHz]
int j=0;
int k=0;

void setup() {
// put your setup code here, to run once:

// Genrating the duty cycle table for sinusoidal PWM

for(int i = 0; i < SinDivisions/2; ++i){ // Generating the look up table.
temp = sin(i2M_PI/SinDivisions)*period; // the amplitude of the sine wave determine the duty cycle for each pulse
lookUpch1[i] = temp; // Round to integer.
}

// 1- Enable clocks for timer counters
PMC->PMC_PCER0 |=PMC_PCER0_PID27; // TC0 power ON - Timer Counter 0 channel 0 IS TC0 -----Enable clock for pin 2,13 (TIOA0,TIOB0)
PMC->PMC_PCER1 |=PMC_PCER1_PID33; // TC6 power ON - Timer Counter 2 channel 0 IS TC6 -----Enable clock for pin 5,4 (TIOA6,TIOB6)
PMC->PMC_PCER1 |=PMC_PCER1_PID34; // TC7 power ON - Timer Counter 2 channel 1 IS TC7 -----Enable clock for pin 3,10 (TIOA7,TIOB8)
PMC->PMC_PCER1 |=PMC_PCER1_PID35; // TC8 power ON - Timer Counter 2 channel 2 IS TC8 -----Enable clock for pin 11,12 (TIOA8,TIOB8)

// 2- Disable PIO from controling these pins and enable peripheral control of the pins
PIOB->PIO_PDR |= PIO_PDR_P25; // Dsiable pin 2
PIOB->PIO_PDR |= PIO_PDR_P27; // Disable pin 13

PIOC->PIO_PDR |= PIO_PDR_P25; // Dsiable pin 5
PIOC->PIO_PDR |= PIO_PDR_P26; // Disable pin 4

PIOC->PIO_PDR |= PIO_PDR_P28; // Dsiable pin 3
PIOC->PIO_PDR |= PIO_PDR_P29; // Disable pin 10

PIOD->PIO_PDR |= PIO_PDR_P7; // Dsiable pin 11
PIOD->PIO_PDR |= PIO_PDR_P8; // Disable pin 12

// 3- Assign pins to the peripheral function
PIOB->PIO_ABSR |= PIO_PB25B_TIOA0; // Peripheral B
PIOB->PIO_ABSR |= PIO_PB27B_TIOB0; // Peripheral B

PIOC->PIO_ABSR |= PIO_PC25B_TIOA6; // Peripheral B
PIOC->PIO_ABSR |= PIO_PC26B_TIOB6; // Peripheral B

PIOC->PIO_ABSR |= PIO_PC28B_TIOA7; // Peripheral B
PIOC->PIO_ABSR |= PIO_PC29B_TIOB7; // Peripheral B

PIOD->PIO_ABSR |= PIO_PD7B_TIOA8; // Peripheral B
PIOD->PIO_ABSR |= PIO_PD8B_TIOB8; // Peripheral B

// 4- Adjust settings for each pin
// PIN 2,13
TC0->TC_CHANNEL[0].TC_CMR= TC_CMR_TCCLKS_TIMER_CLOCK1| // Set clock as MCK/2 (84/2)MHZ= 42MHZ for pins 2,13 (TIOA0,TIOB0)
TC_CMR_WAVE| // Set the pins 2,13 is waveform mode
TC_CMR_WAVSEL_UP| // UP mode without automatic trigger on RC Compare
TC_CMR_ACPA_SET| // clear TIOA0 (pin 2) with RA compare match
TC_CMR_ACPC_CLEAR; // SET TIOA0 (pin2) with RC compare match

// PIN 5,4
TC2->TC_CHANNEL[0].TC_CMR= TC_CMR_TCCLKS_TIMER_CLOCK1| // Set clock as MCK/2 (84/2)MHZ= 42MHZ for pins 2,13 (TIOA0,TIOB0)
TC_CMR_WAVE| // Set the pins 2,13 is waveform mode
TC_CMR_WAVSEL_UP_RC| // UP mode with automatic trigger on RC Compare
TC_CMR_ACPA_SET| // clear TIOA0 (pin 2) with RA compare match
TC_CMR_ACPC_CLEAR| // SET TIOA0 (pin2) with RC compare match
TC_CMR_BCPB_SET| // clear TIOB0 (pin 13) with RA compare match
TC_CMR_BCPC_CLEAR| // SET TIOB0 (pin 13) with RC compare match
TC_CMR_EEVT_XC0;

// PIN 3,10
TC2->TC_CHANNEL[1].TC_CMR= TC_CMR_TCCLKS_TIMER_CLOCK1| // Set clock as MCK/2 (84/2)MHZ= 42MHZ for pins 2,13 (TIOA0,TIOB0)
TC_CMR_WAVE| // Set the pins 2,13 is waveform mode
TC_CMR_WAVSEL_UP| // UP mode without automatic trigger on RC Compare
TC_CMR_ACPA_SET| // clear TIOA0 (pin 2) with RA compare match
TC_CMR_ACPC_CLEAR| // SET TIOA0 (pin2) with RC compare match
TC_CMR_BCPB_SET| // clear TIOB0 (pin 13) with RA compare match
TC_CMR_BCPC_CLEAR| // SET TIOB0 (pin 13) with RC compare match
TC_CMR_EEVT_XC0;

// PIN 11,12
TC2->TC_CHANNEL[2].TC_CMR= TC_CMR_TCCLKS_TIMER_CLOCK1| // Set clock as MCK/2 (84/2)MHZ= 42MHZ for pins 2,13 (TIOA0,TIOB0)
TC_CMR_WAVE| // Set the pins 2,13 is waveform mode
TC_CMR_WAVSEL_UP| // UP mode with automatic trigger on RC Compare
TC_CMR_ACPA_SET| // clear TIOA0 (pin 2) with RA compare match
TC_CMR_ACPC_CLEAR| // SET TIOA0 (pin2) with RC compare match
TC_CMR_BCPB_SET| // clear TIOB0 (pin 13) with RA compare match
TC_CMR_BCPC_CLEAR| // SET TIOB0 (pin 13) with RC compare match
TC_CMR_EEVT_XC0;

// 5- Set the Frequency for each pin
TC0->TC_CHANNEL[0].TC_RC = 2; //set the frequency for TC0 channel 0 as 21 [MHZ]
TC2->TC_CHANNEL[0].TC_RC = period; // Set the Frequency for TC2 channel 0 as Frequency = MCK/2/TC_RC (250 KHz is this case)
TC2->TC_CHANNEL[1].TC_RC = period; // Set the Frequency for TC2 channel 1 as Frequency = MCK/2/TC_RC (250 KHz is this case)
TC2->TC_CHANNEL[2].TC_RC = period; // Set the Frequency for TC2 channel 2 as Frequency = MCK/2/TC_RC (250 KHz is this case)

//6- Set the duty cycle for each pin
TC0->TC_CHANNEL[0].TC_RA = 1; //duty cycle 50%

TC2->TC_CHANNEL[0].TC_RA = 60; // Set the intial Duty cycle for pin 5 as D = (TC_RA/TC_RC) *100
TC2->TC_CHANNEL[0].TC_RB = 30; // Set the intial duty cycle for pin 4

TC2->TC_CHANNEL[1].TC_RA = 60; // Set the intial Duty cycle for pin 3
TC2->TC_CHANNEL[1].TC_RB = 30; // Set the intial duty cycle for pin 10

TC2->TC_CHANNEL[2].TC_RA = 60; // Set the intial Duty cycle for pin 11
TC2->TC_CHANNEL[2].TC_RB = 30; // Set the intial Duty cycle for pin 12

// 7- Interrupt on RC compare match

TC2->TC_CHANNEL[0].TC_IER = TC_IER_CPCS; // Enable Interrupt on RC compare match for TC7
NVIC_EnableIRQ(TC6_IRQn);

//8- Software trigger and clock enable
TC0->TC_CHANNEL[0].TC_CCR = TC_CCR_SWTRG | TC_CCR_CLKEN;

TC2->TC_CHANNEL[0].TC_CCR = TC_CCR_SWTRG | TC_CCR_CLKEN; // Software trigger TC6 counter and enable
TC2->TC_BCR = TC_BCR_SYNC ; // synchrounize the clock of all TC2 channels

TC2->TC_CHANNEL[1].TC_CCR = TC_CCR_SWTRG | TC_CCR_CLKEN; // Software trigger TC7 counter and enable

TC2->TC_CHANNEL[2].TC_CCR = TC_CCR_SWTRG | TC_CCR_CLKEN; // Software trigger TC8 counter and enable

}

void TC6_Handler() { //
TC2->TC_CHANNEL[0].TC_SR;
TC2->TC_CHANNEL[1].TC_SR;
TC2->TC_CHANNEL[2].TC_SR;
TC0->TC_CHANNEL[0].TC_SR;
TC0->TC_CHANNEL[0].TC_CCR = TC_CCR_SWTRG;

if (k<SinDivisions/2){
TC2->TC_CHANNEL[0].TC_RA = period-lookUpch1[k];
TC2->TC_CHANNEL[0].TC_RB = 0;

while((uint32_t)TC0->TC_CHANNEL[0].TC_CV<28){   // (60/360) *(42[MHZ]/250[KHZ])=28 pulses from TC0 channel 0 equals the phase shift 60 degree
  }
TC2->TC_CHANNEL[1].TC_RA = period-lookUpch1[k];
TC2->TC_CHANNEL[1].TC_RB = 0;
TC2->TC_CHANNEL[1].TC_CCR = TC_CCR_SWTRG;

while((uint32_t)TC0->TC_CHANNEL[0].TC_CV<56){ // (120/360) *(42[MHZ]/250[KHZ])=56 pulses from TC0 channel 0 equals the phase shift 120 degree
}

TC2->TC_CHANNEL[2].TC_RA = period-lookUpch1[k];
TC2->TC_CHANNEL[2].TC_RB = 0;
TC2->TC_CHANNEL[2].TC_CCR = TC_CCR_SWTRG;

 
}

if(k>=SinDivisions/2){
TC2->TC_CHANNEL[0].TC_RB = period-lookUpch1[k-SinDivisions/2];
TC2->TC_CHANNEL[0].TC_RA=0;

while((uint32_t)TC0->TC_CHANNEL[0].TC_CV<28){ // (60/360) *(42[MHZ]/250[KHZ])=28 pulses from TC0 channel 0 equals the phase shift 60 degree
}
TC2->TC_CHANNEL[1].TC_RB = period-lookUpch1[k-SinDivisions/2];
TC2->TC_CHANNEL[1].TC_RA=0;
TC2->TC_CHANNEL[1].TC_CCR = TC_CCR_SWTRG;

while((uint32_t)TC0->TC_CHANNEL[0].TC_CV<56){ // (120/360) *(42[MHZ]/250[KHZ])=56 pulses from TC0 channel 0 equals the phase shift 120 degree
}

TC2->TC_CHANNEL[2].TC_RB = period-lookUpch1[k-SinDivisions/2];
TC2->TC_CHANNEL[2].TC_RA=0;
TC2->TC_CHANNEL[2].TC_CCR = TC_CCR_SWTRG;

}

if(k>=SinDivisions){
k=0;}

++k;

}

void loop() {
// put your main code here, to run repeatedly:

}

IMO the easiest way to generate 3 SPWM signals, shifted by respectively 60 and 120 degrees, is the Sunschro feature of the PWM peripheral.

Example sketches using this synchro feature has been given some time ago in the DUE sub forum.

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.