PWM triggered off of Timer Counter

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)

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