How to generate complementary PWM signals using Arduino Due?

When I was reading the datasheet of the Atmel SAM3X8E, I found that this MCU includes a PWM macrocell which controls 8 channels independently, and that each channel controls two complementary square output waveforms.
The Arduino Due has 4 of the 8 PWM channels mapped to its pwm pins labeled PWM6, PWM7, PWM8, PWM9 on board respectively, as 4 independent single outputs.
What I'm trying to do is to use PWM8 as one of my PWM output, and use the pin44 as its complementary signal, these two pins correspond to the HIGH and LOW output of PWM channel 5, which you will see in the attached DUE pin mapping diagram.
I tried using the PIO_Configure( PIOC, PIO_PERIPH_B, 44, PIO_DEFAULT) to assign the pin44 to the PWM Peripheral Function, but after analogwrite(8,100), only got the pwm signal on PWM8, got no signal on pin44, should be complementary signal out there....
Any suggestions would be appreciated!

1 Like

You can generate PWM signals thru the Timer Counters or the PWM controller or analogWrite().

analogWrite() produces PWM pulses throughout pins 2 to 13, plus DAC0 and DAC1, BUT do not produces complementary pulses. Unlike PWM or TC direct register programming, analogWrite() has only very limited features:

The Arduino DUE supports analogWrite() on pins 2 through 13, plus pins DAC0 and DAC1. Unlike the PWM pins, DAC0 and DAC1 are Digital to Analog converters, and act as true analog outputs.
You do not need to call pinMode() to set the pin as an output before calling analogWrite().

To output complementary pulses, e.g. on pin 44 (PWMH5) and pin 8 (PWML5), you have to program directly the PWM controller. Here is an example sketch to program PWMH2/PWML2 :

void setup () {

  // PWM Set-up on pins PC7 and PA20 (Arduino Pins 39(PWMH2) and 43(PWML2)): see Datasheet chap. 38.5.1 page 973
  PMC->PMC_PCER1 |= PMC_PCER1_PID36;                   // PWM power ON
  
  PWM->PWM_DIS = PWM_DIS_CHID2;                        // Disable PWM channel 2

  // Select Instance=PWM; Signal=PWMH2 (channel 2); I/O Line=PC7 (P7, Arduino pin 39, see pinout diagram) ; Peripheral type =B
  PIOC->PIO_PDR |= PIO_PDR_P7;                          // Set the pin to the peripheral PWM, not the GPIO

  PIOC->PIO_ABSR |= PIO_PC7B_PWMH2;                     // Set PWM pin perhipheral type B

  // Select Instance=PWM; Signal=PWML2 (channel 2); I/O Line=PA20 (P20, Arduino pin 43, see pinout diagram) ; Peripheral=B
  PIOA->PIO_PDR |= PIO_PDR_P20;                          // Set the pin to the peripheral PWM, not the GPIO

  PIOA->PIO_ABSR |= PIO_PA20B_PWML2;                    // Set PWM pin perhipheral type B

  // Enable the PWM channel 2 (see datasheet page 973)

  PWM->PWM_CLK = PWM_CLK_PREA(0) | PWM_CLK_DIVA(42);    // Set the PWM clock rate to 2MHz (84MHz/42). Adjust DIVA for the resolution you are looking for

  PWM->PWM_CH_NUM[2].PWM_CMR = PWM_CMR_CPRE_CLKA;     // The period is left aligned, clock source as CLKA on channel 2

  PWM->PWM_CH_NUM[2].PWM_CPRD = 100;                             // Channel 2 : Set the PWM frequency 2MHz/(2 * CPRD) = F ;

  PWM->PWM_CH_NUM[2].PWM_CDTY = 50;                             // Channel 2: Set the PWM duty cycle to x%= (CDTY/ CPRD)  * 100 % ;

  PWM->PWM_ENA = PWM_ENA_CHID2;

  // Alternately, you can use this format :  REG_PWM_CPRD2 = 50;

}

void loop() {
  
}
1 Like

wouldn't it perhaps be easier to generate a standard pwm signal and then use a MOSFET (perhaps p-channel) to invert it?

What do you call a standard PWM ?

the genuine, non-complementary one.

ard_newbie:
You can generate PWM signals thru the Timer Counters or the PWM controller or analogWrite().

analogWrite() produces PWM pulses throughout pins 2 to 13, plus DAC0 and DAC1, BUT do not produces complementary pulses. Unlike PWM or TC direct register programming, analogWrite() has only very limited features:

analogWrite() - Arduino Reference

The Arduino DUE supports analogWrite() on pins 2 through 13, plus pins DAC0 and DAC1. Unlike the PWM pins, DAC0 and DAC1 are Digital to Analog converters, and act as true analog outputs.
You do not need to call pinMode() to set the pin as an output before calling analogWrite().

To output complementary pulses, e.g. on pin 44 (PWMH5) and pin 8 (PWML5), you have to program directly the PWM controller. Here is an example sketch to program PWMH2/PWML2 :

void setup () {

// PWM Set-up on pins PC7 and PA20 (Arduino Pins 39(PWMH2) and 43(PWML2)): see Datasheet chap. 38.5.1 page 973
  PMC->PMC_PCER1 |= PMC_PCER1_PID36;                  // PWM power ON
 
  PWM->PWM_DIS = PWM_DIS_CHID2;                        // Disable PWM channel 2

// Select Instance=PWM; Signal=PWMH2 (channel 2); I/O Line=PC7 (P7, Arduino pin 39, see pinout diagram) ; Peripheral type =B
  PIOC->PIO_PDR |= PIO_PDR_P7;                          // Set the pin to the peripheral PWM, not the GPIO

PIOC->PIO_ABSR |= PIO_PC7B_PWMH2;                    // Set PWM pin perhipheral type B

// Select Instance=PWM; Signal=PWML2 (channel 2); I/O Line=PA20 (P20, Arduino pin 43, see pinout diagram) ; Peripheral=B
  PIOA->PIO_PDR |= PIO_PDR_P20;                          // Set the pin to the peripheral PWM, not the GPIO

PIOA->PIO_ABSR |= PIO_PA20B_PWML2;                    // Set PWM pin perhipheral type B

// Enable the PWM channel 2 (see datasheet page 973)

PWM->PWM_CLK = PWM_CLK_PREA(0) | PWM_CLK_DIVA(42);    // Set the PWM clock rate to 2MHz (84MHz/42). Adjust DIVA for the resolution you are looking for

PWM->PWM_CH_NUM[2].PWM_CMR = PWM_CMR_CPRE_CLKA;    // The period is left aligned, clock source as CLKA on channel 2

PWM->PWM_CH_NUM[2].PWM_CPRD = 100;                            // Channel 2 : Set the PWM frequency 2MHz/(2 * CPRD) = F ;

PWM->PWM_CH_NUM[2].PWM_CDTY = 50;                            // Channel 2: Set the PWM duty cycle to x%= (CDTY/ CPRD)  * 100 % ;

PWM->PWM_ENA = PWM_ENA_CHID2;

// Alternately, you can use this format :  REG_PWM_CPRD2 = 50;

}

void loop() {
 
}

That works, thanks a lot!