I am working on a Space Vector PWM three phase inverter, but before I do that I need to generate three phase quasi-square waves. To do this i need to vary the duty cycle of three complementary channels to feed the base of 6 transistors. I need the duty cycles of each channel to be varied as follows:
Leg A Leg B Leg C
Circuit Config 1 p n n
Circuit Config 2 p p n
Circuit Config 3 n p n
Circuit Config 4 n p p
Circuit Config 5 n n p
Circuit Config 6 p n p
(These 6 Configs need to be looped to produce a continuous waveform)
where 'p' represents when the upper transistor of the Voltage Source Inverter is on and 'n' represents when the lower transistor of the VSI is on.
What i would like to know is how to configure the Due using the Automatic update via a PDC DMA to achieve this.
I was thinking that when the WRDY gives the interrupt and is ready to receive the new duty cycles, an interrupt handler could be used to increment a counter which would increment a switch case, seeing that it's only 6 different circuit configurations required, 6 cases would be made, and each case would have the duty cycle update value based on which channel's duty cycle needs to be updated.
This is my code:
void setup()
{
PMC->PMC_PCER1 |= PMC_PCER1_PID36; //Enable PWM (Power On)
PWM->PWM_DIS = PWM_DIS_CHID0; //Disable PWM on Channel 0
PIOC->PIO_PDR |= PIO_PDR_P3 | PIO_PDR_P5; // Setting pins 3,5, (DUE Pins 35, 37, 39) to PWM Peripheral, not GPIO
PIOC->PIO_ABSR |= PIO_PC3B_PWMH0 | PIO_PC5B_PWMH1; // Setting pins to Peripheral B
PIOC->PIO_PDR |= PIO_PDR_P2 | PIO_PDR_P4; // Setting pins 2,4, (DUE Pins 34, 36, 38) to PWM Peripheral, not GPIO
PIOC->PIO_ABSR |= PIO_PC2B_PWML0 | PIO_PC4B_PWML1; // Setting pins to Peripheral B
PWM->PWM_CLK = PWM_CLK_PREA(0) | PWM_CLK_DIVA(42); //Set PWM clocke rate to 2MHz (84MHz/42)
PWM->PWM_CH_NUM[0].PWM_CMR = PWM_CMR_CPRE_CLKA; // Period is left aligned,clock source is CLKA on Channel 0
REG_PWM_SCM |= PWM_SCM_SYNC0 | PWM_SCM_SYNC1; // Synchronizing of Channels 0, 1 and 2
REG_PWM_SCM |= PWM_SCM_UPDM_MODE2; // Manual Write of duty-cycle automatic trigger of the update
PWM->PWM_SCUP = PWM_SCUP_UPR(0); // Defining update period (UPR + 1)
PWM_SCM_PTRM == 0; // The WRDY flag in PWM_ISR2 and the PDC transfer request are set to 1 as soon as the update period is elapsed.
REG_PWM_CPRD0 = 1000000; //Channel 0 Period f = 2MHz/(2*CPRD)
REG_PWM_CDTY0 = 0; //Channel 0 Duty Cycle x% = (CDTY/ CPRD)*100%
REG_PWM_CPRD1 = 1000000;
REG_PWM_CDTY1 = 1000000;
PWM->PWM_ENA = PWM_ENA_CHID0; // Enable PWM on Channel 0
NVIC_EnableIRQ(TC0_IRQn); // enable TC0 interrupts
}
void loop()
{
// put your main code here, to run repeatedly:
}
void PWM_Interrupt_Handler()
{
}
I looked at this forum already, and I'm having some difficulty understanding how you used the Automatic update via a PDC DMA and how to apply it to my application.
Post your code (between code tags).
I did, i edited the post and added in the code
I'm not trying to generate a wave on each channel, I'm sending signals to the base of 6 IGBTs toggling them on and off to output the quasi square waves, what I/m using the Due for is to make an Induction Motor Drive.
You didn't use the example sketch I gave you for synchro PWM with automatic aupdate of duty cycle with PDC DMA.
If you declare 3 buffers of 6 elements, BufferA is what you call legA, BufferB is BufferA 2/6 phase shifted from BufferA, and BufferC is 4/6 phase shifted from BufferA.
I've updated my code here but it's not working, the idea is at when WRDY is set and new duty cycles can be received that it's updated in a specific order. I used 2 channels instead of three just to test to see if the LEDs on my bread board would switch every second (1Hz period @ 0 and 100% duty cycle alternating).
byte count = 0;
void setup()
{
PMC->PMC_PCER1 |= PMC_PCER1_PID36; //Enable PWM (Power On)
PWM->PWM_DIS = PWM_DIS_CHID0; //Disable PWM on Channel 0
PIOC->PIO_PDR |= PIO_PDR_P3 | PIO_PDR_P5; // Setting pins 3,5, (DUE Pins 35, 37, 39) to PWM Peripheral, not GPIO
PIOC->PIO_ABSR |= PIO_PC3B_PWMH0 | PIO_PC5B_PWMH1; // Setting pins to Peripheral B
PIOC->PIO_PDR |= PIO_PDR_P2 | PIO_PDR_P4; // Setting pins 2,4, (DUE Pins 34, 36, 38) to PWM Peripheral, not GPIO
PIOC->PIO_ABSR |= PIO_PC2B_PWML0 | PIO_PC4B_PWML1; // Setting pins to Peripheral B
PWM->PWM_CLK = PWM_CLK_PREA(0) | PWM_CLK_DIVA(42); //Set PWM clocke rate to 2MHz (84MHz/42)
PWM->PWM_CH_NUM[0].PWM_CMR = PWM_CMR_CPRE_CLKA; // Period is left aligned,clock source is CLKA on Channel 0
REG_PWM_SCM |= PWM_SCM_SYNC0 | PWM_SCM_SYNC1; // Synchronizing of Channels 0, 1 and 2
REG_PWM_SCM |= PWM_SCM_UPDM_MODE1; // Manual Write of duty-cycle automatic trigger of the update
PWM->PWM_SCUP = PWM_SCUP_UPR(0); // Defining update period (UPR + 1)
PWM->PWM_IER2 = PWM_IER2_WRDY; // Enable Interrupt when WRDY flag is set
//PWM_SCM_PTRM == 0;; // The WRDY flag in PWM_ISR2 and the PDC transfer request are set to 1 as soon as the update period is elapsed.
REG_PWM_CPRD0 = 1000000; //Channel 0 Period f = 2MHz/(2*CPRD)
//REG_PWM_CDTY0 = 0; //Channel 0 Duty Cycle x% = (CDTY/ CPRD)*100%
REG_PWM_CPRD1 = 1000000;
//REG_PWM_CDTY1 = 1000000;
PWM->PWM_ENA = PWM_ENA_CHID0; // Enable PWM on Channel 0
NVIC_EnableIRQ(PWM_IRQn); // enable TC0 interrupts
}
void loop()
{
// put your main code here, to run repeatedly:
}
void PWM_Interrupt_Handler()
{
PWM->PWM_ISR2; // Read ISR2 and clear status register
update_Duty_Cycle();
}
void update_Duty_Cycle()
{
if(count > 3){
count = 0;}
SquareWave(count);
count++;
}
void SquareWave(byte Sector)
{
switch(Sector)
{
case 0:
REG_PWM_CDTYUPD0 = 1000000;
REG_PWM_CDTYUPD1 = 0;
break;
case 1:
REG_PWM_CDTYUPD1 = 1000000;
break;
case 2:
REG_PWM_CDTYUPD0 = 0;
break;
case 3:
REG_PWM_CDTYUPD1 = 0;
break;
default:
break;
}
}
If you can help please do...
UPDM_MODE1 is for manual write (of Duty cycles), not automatic update with PDC DMA.
In PWM_CPRD and PWM_CPRDUPD, how many bits are significant ? ---> to find out the answer, read page 1049, Sam3x datasheet.
I only switched to Mode 1 because I didn't understand how the PDC DMA works, but from my code can you see what I'm trying to achieve? Also in PWM_CPRDUPD, only the first 16 bits are significant, but what does that mean exactly? Is it that the maximum number the register can hold is 65536?