Complementary PWM channels Output

Hi jonnygainz,

To generate synchronous, complementary PWM using method 1 (mode0): manual duty-cycle and trigger update, it's necessary to set the update unlock bit (PWM_SCUC_UPDULOCK) in the Sync Channels Update Control register (SCUC), to trigger once the duty-cycle registers have been changed:

PWM->PWM_SCUC = PWM_SCUC_UPDULOCK;      // Set the update unlock bit to trigger an update at the end of the next PWM period

Here's an example of using 3 synchronous, complementary channels on channel 0 (D34, D35), 1 (D36, D37) and 2 (D38, D39). The PWM is at 50Hz and switches between 25% and 75% duty-cycle every 1/2 second:

// Enable synchronous, complementary output, single-slope PWM at 50Hz on 3 channels (0 to 2), at 50% duty cycle
void setup() {
  // Set-up 6 PWM outputs on 3 complementary channels on on pins D34, D35, D36, D37, D38, and D39 for channels 0 through to 2 respectively
  PMC->PMC_PCER1 |= PMC_PCER1_PID36;                                               // Enable PWM   
  PIOC->PIO_ABSR |= PIO_ABSR_P7 | PIO_ABSR_P6 | PIO_ABSR_P5 | PIO_ABSR_P4 |        // Set the port C PWM pins to peripheral type B
                    PIO_ABSR_P3 | PIO_ABSR_P2; 
  PIOC->PIO_PDR |= PIO_PDR_P7 | PIO_PDR_P6 | PIO_PDR_P5 | PIO_PDR_P4 |             // Set the port C PWM pins to outputs
                   PIO_PDR_P3 | PIO_PDR_P2;
  PWM->PWM_CLK = PWM_CLK_PREA(0) | PWM_CLK_DIVA(84);                               // Set the PWM clock A rate to 1MHz (84MHz/84)
  PWM->PWM_SCM |= PWM_SCM_SYNC2 | PWM_SCM_SYNC1 | PWM_SCM_SYNC0;                   // Set the PWM channels as synchronous                  
  PWM->PWM_CH_NUM[0].PWM_CMR = PWM_CMR_CPRE_CLKA;      // Enable single slope PWM and set the clock source as CLKA for all synchronous channels
  PWM->PWM_CH_NUM[0].PWM_CPRD = 19999;                 // Set the PWM frequency 1MHz/(19999 + 1) = 50Hz for all synchronous channels
  for (uint8_t i = 0; i < 3; i++)                      // Loop for each PWM channel (8 in total)
  {
    PWM->PWM_CH_NUM[i].PWM_CDTY = 9999;                // Set the PWM duty cycle to 50%
  } 
  PWM->PWM_ENA = PWM_ENA_CHID0;                        // Enable all synchronous PWM channels
  PWM->PWM_SCUC = PWM_SCUC_UPDULOCK;      // Set the update unlock bit to trigger an update at the end of the next PWM period
}

void loop() 
{
  for (uint8_t i = 0; i < 3; i++)                      // Loop for each PWM channel (3 in total)
  {
    PWM->PWM_CH_NUM[i].PWM_CDTYUPD = 4999;             // Set the PWM duty cycle to 25%
  }
  PWM->PWM_SCUC = PWM_SCUC_UPDULOCK;      // Set the update unlock bit to trigger an update at the end of the next PWM period
  delay(500);
  for (uint8_t i = 0; i < 3; i++)                      // Loop for each PWM channel (3 in total)
  {
    PWM->PWM_CH_NUM[i].PWM_CDTYUPD = 14999;            // Set the PWM duty cycle to 75%
  }
  PWM->PWM_SCUC = PWM_SCUC_UPDULOCK;      // Set the update unlock bit to trigger an update at the end of the next PWM period
  delay(500); 
}

Also, the PWM controller's timers and duty-cycle registers (PWM_CDTY and PWM_CDTYUPD) are essentially only 16-bit, therefore it's not possible to load them with values over 65535 (2^16 - 1).