Arduino Due using all hardware PWM channels

Hello All,

For a while I have been using the Arduino Due and have found a lot of information that was a great help on this forum. For this particular thing I could not find something.

Right now I am working on this library where by I want to control all the broken out hardware PWM pins on the Arduino Due.

I have got some working code with which I can control all those PWM pins, however there are a few things I can't solve.

With this post I am hoping to get some answers or pointers in the right direction.

The code:

#define PWM_MAX_DUTY 4096	//12 bits PWM resolution

void setup()
{
	uint32_t dutyCycle = 2048;	//50% duty cycle
	uint8_t pwmPin[17] = { 6, 7, 8, 9, 29, 34, 35, 36, 37, 38, 39, 40, 41, 43, 44, 45, 53 };	//Arduino hardware PWM pins
	uint8_t pwmCh[8] = { PWM_CH0, PWM_CH1, PWM_CH2, PWM_CH3, PWM_CH4, PWM_CH5, PWM_CH6, PWM_CH7 };	//PWM channels

	//configure all hardware PWM pins to work as PWM
	for (int i = 0; i < 18; i++) {

		PIO_Configure(g_APinDescription[pwmPin[i]].pPort,
			PIO_PERIPH_B,
			g_APinDescription[pwmPin[i]].ulPin,
			g_APinDescription[pwmPin[i]].ulPinConfiguration);
	}

	//configure and set duty cycle on all PWM channels 
	for (int i = 0; i < 8; i++) {

		pmc_enable_periph_clk(PWM_INTERFACE_ID);
		PWMC_ConfigureClocks(450 * PWM_MAX_DUTY, 0, VARIANT_MCK);	//set to frequency @450hz @12bits
		PWMC_ConfigureChannel(PWM_INTERFACE, pwmCh[i], PWM_CMR_CPRE_CLKA, 0, 0);
		PWMC_SetPeriod(PWM_INTERFACE, pwmCh[i], PWM_MAX_DUTY); 
		PWMC_EnableChannel(PWM_INTERFACE, pwmCh[i]);
		PWMC_SetDutyCycle(PWM_INTERFACE, pwmCh[i], dutyCycle);
	}
}

void loop()
{

  /* add main program code here */

}

The results:
D06 C24 PWM L7
D07 C23 PWM L6
D08 C22 PWM L5
D09 C21 PWM L4
D34 C2 PWM L0 22x FREQ
D35 C3 PWM H0 22x FREQ INVERTED
D36 C4 PWM L1
D37 C5 PWM H1 INVERTED
D38 C6 PWM L2
D39 C7 PWM H2 INVERTED
D40 C8 PWM L3
D41 C9 PWM H3 INVERTED
D42 A19 PWM H1 NOT WORKING
D43 A20 PWM L2
D44 C19 PWM H5 INVERTED
D45 C18 PWM H6 INVERTED
D53 B14 PWM H2 INVERTED

  • On all of the above pins I get a PWM output except for pin 42.
    Can anyone see why?
  • On pins 34 & 35 I get a frequency that's 22x higher than the other PWM outputs.
    Is there a particular thing that needs to be configured for this PWM channel?
  • All the PWM H channels seem to be inverted in regards to PWM L channels.
    Is there a particular thing that needs to be configured to get them in the same direction?

Thanks in advance for any feedback.

Hi BrandDebiel

  • All the PWM H channels seem to be inverted in regards to PWM L channels.
    Is there a particular thing that needs to be configured to get them in the same direction?

The PWMLx and PWMHx outputs are the inverse of each other. It's possible to change the polarity of a given PWM channel by setting the CPOL (Channel Polarity) bit in the corresponding PWM Channel Mode Register (PWM_CMRx), but it isn't possible to get the both PWMLx and PWMHx outputs going in the same direction.

Right now I am working on this library where by I want to control all the broken out hardware PWM pins on the Arduino Due.

The SAM3X8E has only 8 full PWM channels. The port mulitplexing just gives you a selection of pins on which you can output these 8 channels. If you require more than 8, it's also possible to use its TC Timer Counters, but these have more limited PWM functionality.

You can also breakout the PWM signals on other pins as well, for example DAC1, A8, A9 and A10. A full list of the port multiplexing is given on pages 50-53 of the SAM3X/A datasheet.

Thanks for the clear reply MartinL! :slight_smile:

Still two things that are not clear to me. Maybe you or somebody else can clarify that.

When I only configure PWM L0 on pin D34 I get the predicted 450hz 12bits PWM output. However when I configure all PWM L0 - L7 on the corresponding pins, it seems that PWM L0 gets a higher frequency. Attached two shots from the logic analyzer. Does anyone know why this is?

PIO_Configure(g_APinDescription[pwmPin[i]].pPort,
	PIO_PERIPH_B,
	g_APinDescription[pwmPin[i]].ulPin,
	g_APinDescription[pwmPin[i]].ulPinConfiguration);

I use this code to configure the pins. As far as I can see this function takes the information from variant.cpp. When I change the definitions in, for example, PIN 34 to PIO_PERIPH_B it does not seem to take this information and use it to configure the PWM right for this pin.

From variant.cpp:

extern const PinDescription g_APinDescription[]=

{ PIOC, PIO_PC2, ID_PIOC, PIO_PERIPH_B, PIO_DEFAULT, PIN_ATTR_DIGITAL,NO_ADC, O_ADC, NOT_ON_PWM,  NOT_ON_TIMER }, // PIN 34

I already tried it with changing all the other information like NOT_ON_PWM and (PIN_ATTR_DIGITAL | PIN_ATTR_PWM) but all I do it does not seem to make any difference.

That's why in the code above PIO_PERIPH_B is fixed and I do not use the function to get it. Does anyone know why I can not take the changed information from variant.cpp? Or is there a better way of doing it by for making my own function for example so that I do not have to take the information from variant.cpp?

Thanks in advance for your information.

Just found out then when I do not configure PWML0 first but start with PWML7 and work my way down to PWML0 all frequencies including channel PWML0 are all 450Hz.

Do not have a clear explanation for it but it does the job.