In my project I am using 1 timer channel (TC0 Ch1 = TC1) to be a 10 kHz clock to which all other outputs/calculations made by the microcontroller is tied to.
Now I want to get an output PWM on the PWMH0 and PWML0 complementary pins, which is in sync with the 10 kHz clock (thus meaning that its frequency is a multiple of 10 kHz) i.e, its rising edges are at same instant of time, but the duty cycle can be varied.
Is there a way to do this without having to use another extra TC? I am using TC2 which is tied to TC1 10 kHz clock, and then inside the TC2 handler, I enable the PWM output and get a non-constant On time PWM output so that the PWM output's rising edge is matched with the TC1 rising edge.
unsigned short duty0[] = {3780, 3780, 3779, 3777, 3775, 3773, 3769, 3765, 3761, 3756, 3750, 3744, 3737, 3730, 3722, 3713, 3704, 3694, 3684, 3673, 3662, 3650, 3637, 3624, 3611, 3597, 3582, 3567, 3551, 3535, 3518, 3501, 3483, 3465, 3446, 3427, 3407, 3387, 3366, 3345, 3324, 3302, 3280, 3257, 3234, 3210, 3186, 3162, 3137, 3112, 3086, 3060, 3034, 3008, 2981, 2954, 2926, 2898, 2870, 2842, 2814, 2785, 2756, 2726, 2697, 2667, 2637, 2607, 2577, 2546, 2516, 2485, 2454, 2423, 2392, 2360, 2329, 2298, 2266, 2235, 2203, 2171, 2140, 2108, 2076, 2045, 2013, 1981, 1950, 1918, 1887, 1855, 1824, 1793, 1762, 1731, 1700, 1669, 1638, 1608, 1578, 1548, 1518, 1488, 1459, 1430, 1401, 1372, 1344, 1315, 1288, 1260, 1233, 1206, 1179, 1153, 1127, 1101, 1076, 1051, 1026, 1002, 978, 955, 932, 909, 887, 865, 844, 823, 803, 783, 764, 745, 726, 708, 691, 674, 657, 641, 626, 611, 596, 582, 569, 556, 544, 532, 521, 511, 501, 491, 482, 474, 467, 459, 453, 447, 442, 437, 433, 429, 426, 424, 422, 421, 420, 420, 421, 422, 424, 426, 429, 433, 437, 442, 447, 453, 459, 467, 474, 482, 491, 501, 511, 521, 532, 544, 556, 569, 582, 596, 611, 626, 641, 657, 674, 691, 708, 726, 745, 764, 783, 803, 823, 844, 865, 887, 909, 932, 955, 978, 1002, 1026, 1051, 1076, 1101, 1127, 1153, 1179, 1206, 1233, 1260, 1288, 1315, 1344, 1372, 1401, 1430, 1459, 1488, 1518, 1548, 1578, 1608, 1638, 1669, 1700, 1731, 1762, 1793, 1824, 1855, 1887, 1918, 1950, 1981, 2013, 2045, 2076, 2108, 2140, 2171, 2203, 2235, 2266, 2298, 2329, 2360, 2392, 2423, 2454, 2485, 2516, 2546, 2577, 2607, 2637, 2667, 2697, 2726, 2756, 2785, 2814, 2842, 2870, 2898, 2926, 2954, 2981, 3008, 3034, 3060, 3086, 3112, 3137, 3162, 3186, 3210, 3234, 3257, 3280, 3302, 3324, 3345, 3366, 3387, 3407, 3427, 3446, 3465, 3483, 3501, 3518, 3535, 3551, 3567, 3582, 3597, 3611, 3624, 3637, 3650, 3662, 3673, 3684, 3694, 3704, 3713, 3722, 3730, 3737, 3744, 3750, 3756, 3761, 3765, 3769, 3773, 3775, 3777, 3779, 3780, 3780};
//Major modes
int Idle = 0;
int runmode = 1;
int State = Idle; //Initially Start off with Idle mode
void pwmc_setup()
{ // Configure PWM channels 0,1,2,3,5,6 (channels 4 and 7 don't have PWMH)
// Signals : PWML0,PWMH0,PWML1,PWMH1,PWML2,PWMH2,PWML3,PWMH3,PWML5,PWMH5,PWML6,PWMH6
// SAM3X Pin: PC2 ,PC3 ,PC4 ,PC5 ,PC6 ,PC7 ,PC8 ,PC9 ,PC22 ,PC19 ,PC23 ,PC18
// Due Pins : P34 ,P35 ,P36 ,P37 ,P38 ,P39 ,P40 ,P41 ,P8 ,P44 ,P7 ,P45
REG_PIOC_PDR = 0xFFFFFFFF; // PIO Disable Register, enables peripheral control of pin
REG_PIOC_ABSR = 0xFFFFFFFF; // AB Select Register, 0 = A selected, 1 = B selected
REG_PMC_PCER1 = REG_PMC_PCER1 | 16; //Peripheral Clock Enable Register 1 (activate clock for PWM, id36, bit5 of PMC_PCSR1)
REG_PWM_ENA = REG_PWM_SR | B00000001; //PWM Enable Register | PWM Status Register (activate channel 0)
REG_PWM_CMR0 = 0x10000; //Channel0 Mode Register: Dead Time Enable DTE=1
// Adjust deadtime
REG_PWM_DT0 = 0x0E000E; //Channel0 Dead Time Register (14=167ns for outputs PWML0,PWMH0)
REG_PWM_CPRD0 = 4200; //Channel0 Period Register (84mhz/4200=20kHz=50us period)
}
void setup(){ Serial.begin(9600);
//RGB1 off on start up
pinMode(R1,OUTPUT); //R1
pinMode(G1,OUTPUT); // G1
pinMode(B1,OUTPUT); // B1
digitalWrite(R1, LOW); digitalWrite(G1,LOW); digitalWrite(B1,LOW); //All colours OFF
/////////////////////////////////
pinMode(DIP1,INPUT); // DIP 1
pinMode(DIP2,INPUT); //DIP 2
pinMode(DIP3,INPUT); //DIP 3
pinMode(DIP4,INPUT);//DIP 4
////////////////////////////////////
pinMode(TOG1, INPUT); //Toggle Switch 1
////////////////////////////////////
pinMode(ADC_11,INPUT); //A11 ADC for potentiometer
///////////////////////////////////////////////////
/// TIMER BIG CLOCK ////////////
PMC->PMC_PCER0 |= PMC_PCER0_PID27; //Enable TC0 peripheral
PIOC->PIO_ABSR |= PIO_ABSR_P23; //PWML6, Pin C.23
PIOC->PIO_PDR |= PIO_PDR_P23; //Disable GPIO on this output pin
// TC1 is used to set up a 4 kHz clock to which all else is synced
TC0->TC_CHANNEL[1].TC_CMR = TC_CMR_BCPC_SET | // Set TIOB on counter match with RC0
TC_CMR_ACPC_SET | // Set TIOA on counter match with RC0
TC_CMR_BCPB_CLEAR | // Clear TIOB on counter match with RB0
TC_CMR_ACPA_CLEAR | // Clear TIOA on counter match with RA0
TC_CMR_WAVE | // Enable wave mode
TC_CMR_WAVSEL_UP_RC | // Count up with automatic trigger on RC compare
TC_CMR_EEVT_XC0 | // Set event selection to XC0 to make TIOB an output
TC_CMR_TCCLKS_TIMER_CLOCK1; // Set the timer clock to TCLK1 (MCK/2)
TC0->TC_CHANNEL[1].TC_RA = 5250;
TC0->TC_CHANNEL[1].TC_RC = 10500; //TC0 Ch1 runs at 4 kHz clock (State Machine)
TC0->TC_CHANNEL[1].TC_CCR = TC_CCR_SWTRG | TC_CCR_CLKEN; //Enabling timer TC1
NVIC_SetPriority(TC0_IRQn, 0); // Set the Nested Vector Interrupt Controller (NVIC) priority for TC0 to 0 (highest)
NVIC_EnableIRQ(TC0_IRQn);
TC0->TC_CHANNEL[1].TC_IER = TC_IER_CPCS | TC_IER_ETRGS; // Enable interrupts for TC0 (TC0 Channel 1)
//////////////////////
pwmc_setup();
}
void TimerStart(Tc *tc, uint32_t channel, IRQn_Type irq, uint32_t freq)
{
pmc_set_writeprotect(false);
pmc_enable_periph_clk(irq);
TC_Configure(tc, channel, TC_CMR_WAVE | TC_CMR_WAVSEL_UP_RC |
TC_CMR_TCCLKS_TIMER_CLOCK1);
uint32_t rc = 10500; //Same as 4kHz state machine clock
TC_SetRA(tc, channel, rc >> 1);
TC_SetRC(tc, channel, rc);
// Timer is stopped after configuration
TC_Start(tc, channel); // Restart with TC_Start(), all interrupts are disabled
tc->TC_CHANNEL[channel].TC_IER= TC_IER_CPCS | TC_IER_CPAS;
tc->TC_CHANNEL[channel].TC_IDR=~(TC_IER_CPCS | TC_IER_CPAS);
NVIC_EnableIRQ(irq);
}
void TC2_Handler()
{
TC_GetStatus(TC0, 2);
static int num; static char trig;
// Change duty cycle every period
REG_PWM_CDTY0 = duty0[num];
if(++num >= 333){ // Pre-increment num then check if it's below number of samples (USER INPUT)
num = 0; // reset num
trig = trig^0b00000001;
}
}
void state_idle(){ //Indicated by R1
//For direct port bit manipulation write as
PIOC -> PIO_SODR = 1 << 14; //R1 (pin 49 = C.14) RED ON
PIOC -> PIO_CODR = 1 << 12; // pin 51 = C.12 GREEN OFF
PIOB -> PIO_CODR = 1 << 14; // pin 53 = B.14 BLUE OFF
/* // Reading direct bits (Needs to be checked)
statusR1 = (PIOC->PIO_PDSR) |0xE;
statusG1 = (PIOC->PIO_PDSR) |0xC;
statusB1 = (PIOB->PIO_PDSR) |0xE;
*/
if(digitalRead(TOG1)==1){ //Pin 31 = Tog1
State=runmode;
}
//delay(100); //Necessary only for Push Button, not needed here for Tog switch
}
void state_runmode(){ //Indicated by G1
//For direct port bit manipulation write as
PIOC -> PIO_CODR = 1 << 14; //R1 (pin 49 = C.14) RED OFF
PIOC -> PIO_SODR = 1 << 12; // pin 51 = C.12 GREEN ON
PIOB -> PIO_CODR = 1 << 14; // pin 53 = B.14 BLUE OFF
// Giving PWM output on channel 0 //
TimerStart(TC0, 2, TC2_IRQn, 20000);
//-----------------------------------------------
if(digitalRead(TOG1)==0){
TC_Stop(TC0, 2);
REG_PWM_DIS = REG_PWM_SR | B00000001; //Disables PWM output on Channel 0
State=Idle;
}
}
///////////////////// State Machine Runs continuously //////////////
void loop(){
if(State==Idle)
{ Serial.println(State); //Check with serial monitor on IDE
state_idle();
}
else if(State==runmode)
{Serial.println(State); //Check with Serial monitor on IDE
state_runmode();
}
}
(In the runmode state, the PWM output should be complementary at PWM channel 0)