Programmable PWM Frequency

Hello,

I am currently working on a project and have run into a wall. I need to be able to generate a PWM wave with an adjustable frequency (0 - 10kHZ) with a resolution of ~ 10Hz. This also has to have a Duty cycle of 0-100, with resolution ~1. Is this possible with the Due? I know that pin 9 acts as a true PWM output, but after searching for awhile I couldn't find any straightforward answers. If this isn't possible, are there any hardware solutions, I have looked into programmable oscillators with no luck, as well as PLL's, the last thing I can think of is silly, but an FPGA could do it!

Hi there Julian,

Have a look to pwm_lib, you can use example basic_test.ino as an starting point. The library is available at:

If in any doubt, just let me know.

I hope it helps.

@julianbostick . Hello Julian

As a simple example of PWM implementation, you could try this :

void setup() {
  // PWM Set-up on pin PC7 (Arduino Pin 39): see Datasheet chap. 38.5.1
  // Select Instance=PWM; Signal=PWMH2 (channel 2); I/O Line=PC7 (P7, Arduino pine 39, see pinout diagram) ; Peripheral=B

  PMC->PMC_PCER1 |= PMC_PCER1_PID36;                   // Enable PWM 
  
  REG_PIOC_ABSR |= PIO_ABSR_P7;                        // Set PWM pin perhipheral type B
  REG_PIOC_PDR |= PIO_PDR_P7;                          // Set PWM pin to an output

  REG_PWM_ENA = PWM_ENA_CHID2;                         // Enable the PWM channel 2 (see datasheet page 973) 
 
  REG_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
                                                       // I suspect that the smaller the DIVA factor, the higher the resolution will be
  REG_PWM_CMR2 = PWM_CMR_CALG |PWM_CMR_CPRE_CLKA;      // The period is left aligned, clock source as CLKA on channel 2
  REG_PWM_CPRD2 = 1000000;                             // Channel 2 : Set the PWM frequency 2MHz/(2 * CPRD) = F ; 1< CPRD < 2exp24  -1 ; here CPRD = 10 exp 6
  REG_PWM_CDTY2 = 200000;                              // Channel 2: Set the PWM duty cycle to x%= (CDTY/ CPRD)  * 100 % ; here CDTY = 2 * 10 exp 5
 // Alternatively, you can use this format :  PWM->PWM_CH_NUM[2].PWM_CPRD = 1000000 ;  

                   
 // In this example, Frequency is 1 HZ with a DT of 20% so you can see it with an LED attached to pin 39 with a resistor  
  
  Serial.begin(250000); // for debugging purpose
}

void loop() {
 
// If you want to modify the PWM frequency during operation :
REG_PWM_CPRDUPD2 = 800000;
REG_PWM_SCM = PWM_SCM_UPDM_MODE0 ;
REG_PWM_SCUC = PWM_SCUC_UPDULOCK;

//delay(1000);


 // if you want to modify duty cycle during operation:
REG_PWM_CDTYUPD2 = 50000;
REG_PWM_SCM = PWM_SCM_UPDM_MODE0 ;
REG_PWM_SCUC = PWM_SCUC_UPDULOCK;
 
//delay(1000);

  }