I have been searching for the correct methods for last 2 days, I went through datasheet & other resources in the internet and here is what I've come up with.
This is based on the code Collin80 provided me. Thanks again Collin.
This code should create 10 bit, Synchronous, 3 Complimentary, center aligned PWM and updates the value at the Interrupt on the Max value of the counter.
Anyone please tell me if I'm right? Is anything else needed to get it complete?
I don't have an oscilloscope so I cant validate the correctness of the code.
/* DUE PWM
CHANNEL: 3
COMPLIMENTARY OUTPUTS: 3 HIGH + 3 LOW
SYNC: ALL
FREQUENCY: 2 KHz
MAX_PWM_DUTY: 1023 (10 BIT)
PWM_TARGET_DEADTIME 600 nS
*/
#include <Arduino.h>
#include "pwm.h"
#include "config.h"
void setup_pwm()
{
//pinMode(42, OUTPUT);
pmc_enable_periph_clk (PWM_INTERFACE_ID) ; // turn on clocking to PWM unit
PWMC_DisableChannel(PWM_INTERFACE, 0);
PWMC_DisableChannel(PWM_INTERFACE, 1);
PWMC_DisableChannel(PWM_INTERFACE, 2);
// Configure (PC2) through (PC7) to be PWM now(for complimentary PWM output. i.e. PC2 = low, PC3= high).
// This causes all of them to be PWM channels 0, 1, 2
// C7 C6 C5 C4 C3 C2 C1 C0
// 1 1 1 1 1 1 0 0 => 0b11111100 = 0xFC
PIOC->PIO_PDR = 0xFC; // 0b11111100 disable PIO control for all of them
PIOC->PIO_IDR = 0xFC; // 0b11111100 disable PIO interrupts for all of them
PIOC->PIO_ABSR |= 0xFC; // 0b11111100 switch to B peripheral
//assuming 2KHz and 1023 that would be a clock of 4.092 MHz (Center aligned is twice speed)
PWMC_ConfigureClocks((unsigned int)PWM_FREQ * MAX_PWM_DUTY * 2, 0, VARIANT_MCK );
//find the number of ticks necessary to ensure that dead time is at least as long as requested.
int deadTicks = ((VARIANT_MCK * 1000ul) / ((unsigned int)PWM_FREQ * MAX_PWM_DUTY) / (unsigned int)PWM_TARGET_DEADTIME) + 1;
deadTicks = 40;
// PWM, Chan, Clock, Left/Center, Polarity, CountEvent, DeadEnable, DeadHighInv, DeadLowInv
// CHANNEL 0
PWMC_ConfigureChannelExt(PWM_INTERFACE, 0, PWM_CMR_CPRE_CLKA, PWM_CMR_CALG, 0, 0, PWM_CMR_DTE, 0, 0);
PWMC_SetPeriod (PWM_INTERFACE, 0, 1023) ; // period = 525 ticks (10Khz), every tick is 1/5.25 micro seconds
PWMC_SetDutyCycle (PWM_INTERFACE, 0, 0); //set duty cycle of channel 0 to 0 (duty is out of the period above so min is 0 max is 525)
PWMC_SetDeadTime(PWM_INTERFACE, 0, deadTicks, deadTicks) ; //set a bit of dead time around all transitions
// CHANNEL 1
PWMC_ConfigureChannelExt (PWM, 1, PWM_CMR_CPRE_CLKA, PWM_CMR_CALG, 0, 0, PWM_CMR_DTE, 0, 0);
PWMC_SetPeriod (PWM, 1, 1023) ;
PWMC_SetDutyCycle (PWM, 1, 0); //set duty cycle of channel 0 to 0 (duty is out of the period above
PWMC_SetDeadTime(PWM, 1, deadTicks, deadTicks) ; //set some dead time
// CHANNEL 2
PWMC_ConfigureChannelExt (PWM, 2, PWM_CMR_CPRE_CLKA, PWM_CMR_CALG, 0, 0, PWM_CMR_DTE, 0, 0);
PWMC_SetPeriod (PWM, 2, 1023) ;
PWMC_SetDutyCycle (PWM, 2, 0); //set duty cycle of channel 0 to 0 (duty is out of the period above
PWMC_SetDeadTime(PWM, 2, deadTicks, deadTicks) ; //set some dead time
// SYNCHRONISM OF PWM CHANNELS
PWMC_ConfigureSyncChannel(PWM_INTERFACE, 7, 0, 0,0); //make channels 0, 1, 2 be synchronous ie 0b0000...0111
PWMC_SetSyncChannelUpdatePeriod(PWM_INTERFACE, 1); //PWMC_SetSyncChannelUpdatePeriod(PWM_INTERFACE, PWM_Period)
PWMC_ConfigureChannelExt(PWM_INTERFACE, 0, PWM_CMR_CPRE_CLKA, PWM_CMR_CALG, 0, 0, PWM_CMR_DTE, 0, 0);
PWMC_ConfigureChannelExt(PWM_INTERFACE, 1, PWM_CMR_CPRE_CLKA, PWM_CMR_CALG, 0, 0, PWM_CMR_DTE, 0, 0);
PWMC_ConfigureChannelExt(PWM_INTERFACE, 2, PWM_CMR_CPRE_CLKA, PWM_CMR_CALG, 0, 0, PWM_CMR_DTE, 0, 0);
// Start of Interrupts declaration
//Enable of the Interrupts (writing CHIDx in PWM_IER1 register, and writing WRDYE, CMPMx in PWM_IER2 register)
PWM_INTERFACE->PWM_IER1 = 0x01; //0b0000 0000 0000 0000 0000 0000 0000 0001--enable CHID0 on channel 0
PWM_INTERFACE->PWM_IDR1 = 0xFFFFFFFE; //0b1111 1111 1111 1111 1111 1111 1111 1110--enable CHID0 on channel 0
PWM_INTERFACE->PWM_IER2 = 0x101; //0b0000 0000 0000 0000 0000 0001 0000 0001--enable WRDY => 0 & CMPM0 => 8 on channel 0
PWM_INTERFACE->PWM_IDR2 = 0xFFFFFEFE; //0b1111 1111 1111 1111 1111 1110 1111 1110--enable WRDY => 0 & CMPM0 => 8 on channel 0
// Setup NVIC interrupt
NVIC_DisableIRQ(PWM_IRQn);
NVIC_ClearPendingIRQ(PWM_IRQn);
NVIC_SetPriority(PWM_IRQn, 0);
NVIC_EnableIRQ((IRQn_Type)36);
/*
// Enable
PWMC_EnableChannelIt(PWM_INTERFACE, 0);
*/
PWMC_EnableChannel (PWM_INTERFACE, 0) ; // enable
PWMC_EnableChannel (PWM_INTERFACE, 1) ; // enable
PWMC_EnableChannel (PWM_INTERFACE, 2) ; // enable
}
void loop() {
}
void PWM_Handler(void) // PWM interrupt handler Occurs @ INTERRUPT as shown in 'SYNC PWM.jpg'
{
volatile long dummy = PWM_INTERFACE->PWM_ISR1; // clear interrupt flag
dummy = PWM_INTERFACE->PWM_ISR2; // clear interrupt flag
flag = TRUE; // Calculation start flag for my program
PWMC_SetDutyCycle (PWM_INTERFACE, 0, a);
PWMC_SetDutyCycle (PWM_INTERFACE, 1, b);
PWMC_SetDutyCycle (PWM_INTERFACE, 2, c);
PWMC_SetSyncChannelUpdateUnlock(PWM_INTERFACE); //enable setting of all those duties all at once
}
Though I do not understand utility of
PWMC_EnableChannelIt(PWM_INTERFACE, channel);
hence I kept it under comment and changed it to work with channel 0 if necessary.
can anyone please describe its functionality?
Thanks in advance.
Sourav