Complementary PWM channels Output

This example shows how it works for 1 channel, how does dead time work for three synchronized channels? like how I have CH0, CH1 and CH2 synchronized.

This example shows how it works for 1 channel, how does dead time work for three synchronized channels? like how I have CH0, CH1 and CH2 synchronized.

You just have to set the dead time enable bit for each channel:

PWM->PWM_CH_NUM[1].PWM_CMR = PWM_CMR_DTE;                         // Enable channel 1 dead-time insertion

Here's an example with 3 pairs of complementary and synchronous PWM outputs at 100kHz:

// Enable synchronous, complementary output, single-slope PWM at 100kHz on 3 channels (0 to 2), at 75% duty cycle
// with various dead-times for each channel
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 |                     // Set the port C PWM pins to peripheral type B
                    PIO_ABSR_P5 | PIO_ABSR_P4 |
                    PIO_ABSR_P3 | PIO_ABSR_P2; 
  PIOC->PIO_PDR |= PIO_PDR_P7 | PIO_PDR_P6 |                        // Set the port C PWM pins to outputs
                   PIO_PDR_P5 | PIO_PDR_P4 |
                   PIO_PDR_P3 | PIO_PDR_P2;                 
  PWM->PWM_CLK = PWM_CLK_PREA(0) | PWM_CLK_DIVA(1);                 // Set the PWM clock A rate to 84MHz (84MHz/1)
  PWM->PWM_SCM |= PWM_SCM_UPDM_MODE1 |                              // Automatically update the duty-cycle register each timer cycle                    
                  PWM_SCM_SYNC2 | PWM_SCM_SYNC1 | PWM_SCM_SYNC0;    // Set the PWM channels as synchronous                  
  PWM->PWM_CH_NUM[0].PWM_CPRD = 839;                                // Set the PWM frequency to 100kHz (84MHz/(839 + 1)) for all synchronous channels
  PWM->PWM_CH_NUM[0].PWM_CMR = PWM_CMR_DTE | PWM_CMR_CPRE_CLKA;     // Enable channel 0 dead-time insertion and set the clock source as CLKA for all synchronous channels
  PWM->PWM_CH_NUM[1].PWM_CMR = PWM_CMR_DTE;                         // Enable channel 1 dead-time insertion
  PWM->PWM_CH_NUM[2].PWM_CMR = PWM_CMR_DTE;                         // Enable channel 2 dead-time insertion
  PWM->PWM_CH_NUM[0].PWM_CDTY = 630;                                // Set channel 0 PWM duty cycle to 75%
  PWM->PWM_CH_NUM[1].PWM_CDTY = 630;                                // Set channel 1 PWM duty cycle to 75%
  PWM->PWM_CH_NUM[2].PWM_CDTY = 630;                                // Set channel 2 PWM duty cycle to 75%
  PWM->PWM_CH_NUM[0].PWM_DT = PWM_DT_DTH(0) | PWM_DT_DTL(0);        // Set channel dead-time for a 0us delay on output PWML0
  PWM->PWM_CH_NUM[1].PWM_DT = PWM_DT_DTH(0) | PWM_DT_DTL(105);      // Set channel dead-time for a 1.25us delay on output PWML1
  PWM->PWM_CH_NUM[2].PWM_DT = PWM_DT_DTH(0) | PWM_DT_DTL(210);      // Set channel dead-time for a 2.5us delay on output PWML2
  PWM->PWM_ENA = PWM_ENA_CHID0;                                     // Enable all synchronous PWM channels
}

void loop() {}

Here's the output top to bottom of channels PWML0, PWML1, PWML2 and PWMH0 respectively:

DeadTimeInsertion3.png

PWML0 (yellow) and its complement PWMH0 (dark blue) have no dead-time insertion, PWML1 (light blue) has 1.25us of dead-time insertion, while PWML2 (pink) has 2.5us.

DeadTimeInsertion3.png

How do I update the dead time every period, because I tried what you showed me in #26 but the dead times aren't being inserted. I'm still just getting both complementary wave-forms being exactly the same.

/* This code generates Quasi-Square Waves at 60Hz*/
static byte stateCount = 0;
static float CPRDV = 0;
static float inverterFrequency = 60;
int divA = 42;      // Set DIVA

void setup()
{
  Serial.begin(57600);
  PMC->PMC_PCER1 |= PMC_PCER1_PID36;                  // Enable PWM (Power On)

  PIOC->PIO_PDR |= PIO_PDR_P3 | PIO_PDR_P5 | PIO_PDR_P7;           // Setting pins 3,5,7 (DUE Pins 35, 37, 39) to PWM Peripheral, not GPIO
  PIOC->PIO_ABSR |= PIO_ABSR_P3 | PIO_ABSR_P5 | PIO_ABSR_P7;       // Setting pins to Peripheral B

  PIOC->PIO_PDR |= PIO_PDR_P2 | PIO_PDR_P4 | PIO_PDR_P6;           // Setting pins 2,4,6 (DUE Pins 34, 36, 38) to PWM Peripheral, not GPIO
  PIOC->PIO_ABSR |= PIO_ABSR_P2 | PIO_ABSR_P4 | PIO_ABSR_P6;       // Setting pins to Peripheral B

  PWM->PWM_CLK = PWM_CLK_PREA(0) | PWM_CLK_DIVA(divA);  // Set PWM clocke rate to 2MHz (84MHz/42)
  PWM->PWM_SCM |= PWM_SCM_SYNC0 | PWM_SCM_SYNC1 | PWM_SCM_SYNC2;      // Synchronizing of Channels 0, 1 and 2
  PWM->PWM_SCM |= PWM_SCM_UPDM_MODE1;                 // Manual Write of duty-cycle automatic trigger of the update
  
  NVIC_SetPriority(PWM_IRQn, 0);                      // Set the Nested Vector Interrupt Controller (NVIC) priority for the PWM controller to 0 (highest)
  NVIC_EnableIRQ(PWM_IRQn);                           // Connect PWM Controller to Nested Vector Interrupt Controller (NVIC)

  PWM->PWM_IER1 = PWM_IER1_CHID0;                     // Enable interrupt on PWM channel 0 triggered at end of PWM period

  calcCPRDV();  // CPRD is calculated
  /*Serial.print("CPRDV = ");
  Serial.print(CPRDV);
  Serial.print("\n");*/
  PWM->PWM_CH_NUM[0].PWM_CPRD = CPRDV;                // Channel 0 Period f = 2MHz/(CPRD)= 100Hz = 0.01s |CPRD = 2MHz/f
  PWM->PWM_CH_NUM[0].PWM_CMR = PWM_CMR_CPRE_CLKA | PWM_CMR_DTE;     // Period is left aligned,clock source is CLKA on Channel 0
  PWM->PWM_CH_NUM[1].PWM_CMR = PWM_CMR_DTE;
  PWM->PWM_CH_NUM[2].PWM_CMR = PWM_CMR_DTE;

  PWM->PWM_CH_NUM[0].PWM_DT = PWM_DT_DTH(0)| PWM_DT_DTL(2);   
  PWM->PWM_CH_NUM[1].PWM_DT = PWM_DT_DTH(0)| PWM_DT_DTL(2); // Dead time of 1us [DT = (1/2778)*5555 = 2
  PWM->PWM_CH_NUM[2].PWM_DT = PWM_DT_DTH(0)| PWM_DT_DTL(2);
  
  PWM->PWM_ENA = PWM_ENA_CHID0;                       // Enable synchronous PWM on Channel 0
}

void loop()
{
  
}

void PWM_Handler()                       // PWM Interrupt Service Routine (ISR)
{
  if (PWM->PWM_ISR1 & PWM_ISR1_CHID0)    // Check if an update condition has occured
  {       
    update_Duty_Cycle();                 // Update the duty cycles
  }
}

void calcCPRDV () // Used to calculate the CPRD value
{
  //inverterFrequency = 60;
  static float numOfVectors = 6;
  static float adMCKFreq = 84000000;
  static float timerFreq = (adMCKFreq/divA); //2MHz
  static float period = 1/inverterFrequency;
  static float Ts = period/numOfVectors;
  static float switchingFreq = 1/Ts;
  CPRDV = (timerFreq/(1*switchingFreq));
  /*Serial.print("Inverter Frequency = "); Serial.print(inverterFrequency);Serial.print("\n");
  Serial.print("Num of Vectors = "); Serial.print(numOfVectors); Serial.print("\n");
  Serial.print("Timer Freq = "); Serial.print(timerFreq); Serial.print("\n");
  Serial.print("Period = "); Serial.print(period, 8); Serial.print("\n");
  Serial.print("SSV Period = "); Serial.print(Ts, 8); Serial.print("\n");
  Serial.print("Switching Freq = "); Serial.print(switchingFreq); Serial.print("\n");*/

}

void update_Duty_Cycle()
{
  
  
    if(stateCount < 6)
    {
          PWM->PWM_CH_NUM[0].PWM_CDTYUPD = 0;
          PWM->PWM_CH_NUM[1].PWM_CDTYUPD = 0;
          PWM->PWM_CH_NUM[2].PWM_CDTYUPD = 0;
          stateCount++;
          /*Serial.print("Counter = ");
          Serial.print(stateCount); Serial.print("\n");*/
    }
    else
    {
  
      static byte count = 0;
      static float p = CPRDV;
      static float n = 0;
      //Serial.print("Sector = "); Serial.print(count); Serial.print("\n");
      switch(count)
        {
          case 0: //pnn = 100 => 012
            PWM->PWM_CH_NUM[0].PWM_CDTYUPD = p;
            PWM->PWM_CH_NUM[1].PWM_CDTYUPD = n;
            PWM->PWM_CH_NUM[2].PWM_CDTYUPD = n;
            
            PWM->PWM_CH_NUM[0].PWM_DT = PWM_DT_DTH(0)| PWM_DT_DTL(20);
            PWM->PWM_CH_NUM[1].PWM_DT = PWM_DT_DTH(0)| PWM_DT_DTL(20);
            PWM->PWM_CH_NUM[2].PWM_DT = PWM_DT_DTH(0)| PWM_DT_DTL(20);
          break;
          case 1: //ppn = 110 => 012 
            PWM->PWM_CH_NUM[0].PWM_CDTYUPD = p;
            PWM->PWM_CH_NUM[1].PWM_CDTYUPD = p;
            PWM->PWM_CH_NUM[2].PWM_CDTYUPD = n;
          break;
          case 2: //npn = 010 => 012
            PWM->PWM_CH_NUM[0].PWM_CDTYUPD = n;
            PWM->PWM_CH_NUM[1].PWM_CDTYUPD = p;
            PWM->PWM_CH_NUM[2].PWM_CDTYUPD = n;
          break;
          case 3: //npp = 011 => 012
            PWM->PWM_CH_NUM[0].PWM_CDTYUPD = n;
            PWM->PWM_CH_NUM[1].PWM_CDTYUPD = p;
            PWM->PWM_CH_NUM[2].PWM_CDTYUPD = p;
          break;
          case 4: //nnp = 001 => 012
            PWM->PWM_CH_NUM[0].PWM_CDTYUPD = n;
            PWM->PWM_CH_NUM[1].PWM_CDTYUPD = n;
            PWM->PWM_CH_NUM[2].PWM_CDTYUPD = p;
          break;
          case 5: //pnp = 101 => 012
            PWM->PWM_CH_NUM[0].PWM_CDTYUPD = p;
            PWM->PWM_CH_NUM[1].PWM_CDTYUPD = n;
            PWM->PWM_CH_NUM[2].PWM_CDTYUPD = p;
          break;
          default:
          break;
        }
        count = (count + 1) % 6;


    }
}

I just want a deadtime of 1us, my CPRD value is 5555 and my period is 2778us, therefore DT=(1/2778)*55555 = 1.999 = 2. When i look at it on an oscilloscope I'm not seeing the dead time. So I'm thinking that I need to update the dead time every period for them to show up.

Have you zoomed into (with the time base) and compared the leading edges of the synchronised PWM waveforms on your scope? A 1us (1/2MHz * 2) dead-time is hardly anything in comparison to the 2778us period.

During operation it's also possible to use the dead-time insertion update registers. These update the dead-time at the beginning of the next timer cycle, in a similar fashion to the duty-cycle update registers:

PWM->PWM_CH_NUM[0].PWM_DTUPD = PWM_DTUPD_DTHUPD(0) | PWM_DTUPD_DTLUPD(2);

When I try using the code in #28, the IDE tells me "PWM_DT_DTHUPD" and "PWM_DT_DTLUPD" was not declared in this scope.

An yes I zoomed in on the oscilloscope to see if I was getting the dead times, I went as far as 5us and still wasn't seeing the dead times

When I try using the code in #28, the IDE tells me "PWM_DT_DTHUPD" and "PWM_DT_DTLUPD" was not declared in this scope.

I've now corrected it above, it's

PWM->PWM_CH_NUM[0].PWM_DTUPD = PWM_DTUPD_DTHUPD(0) | PWM_DTUPD_DTLUPD(2);

Are your looking at the low side channel outputs, PWMLx, on your scope?

I'm looking at both low side and high side for each channel in turn to compare.

I tried the code in #30 and still nothing. This is my code:

/* This code generates Quasi-Square Waves at 60Hz*/
static byte stateCount = 0;
static float CPRDV = 0;
static float inverterFrequency = 60;
int divA = 42;

void setup()
{
  //Serial.begin(57600);
  PMC->PMC_PCER1 |= PMC_PCER1_PID36;                  // Enable PWM (Power On)

  PIOC->PIO_PDR |= PIO_PDR_P3 | PIO_PDR_P5 | PIO_PDR_P7;           // Setting pins 3,5,7 (DUE Pins 35, 37, 39) to PWM Peripheral, not GPIO
  PIOC->PIO_ABSR |= PIO_ABSR_P3 | PIO_ABSR_P5 | PIO_ABSR_P7;       // Setting pins to Peripheral B

  PIOC->PIO_PDR |= PIO_PDR_P2 | PIO_PDR_P4 | PIO_PDR_P6;           // Setting pins 2,4,6 (DUE Pins 34, 36, 38) to PWM Peripheral, not GPIO
  PIOC->PIO_ABSR |= PIO_ABSR_P2 | PIO_ABSR_P4 | PIO_ABSR_P6;       // Setting pins to Peripheral B

  PWM->PWM_CLK = PWM_CLK_PREA(0) | PWM_CLK_DIVA(divA);  // Set PWM clocke rate to 2MHz (84MHz/42)
  PWM->PWM_SCM |= PWM_SCM_SYNC0 | PWM_SCM_SYNC1 | PWM_SCM_SYNC2;      // Synchronizing of Channels 0, 1 and 2
  PWM->PWM_SCM |= PWM_SCM_UPDM_MODE1;                 // Manual Write of duty-cycle automatic trigger of the update
  
  NVIC_SetPriority(PWM_IRQn, 0);                      // Set the Nested Vector Interrupt Controller (NVIC) priority for the PWM controller to 0 (highest)
  NVIC_EnableIRQ(PWM_IRQn);                           // Connect PWM Controller to Nested Vector Interrupt Controller (NVIC)

  PWM->PWM_IER1 = PWM_IER1_CHID0;                     // Enable interrupt on PWM channel 0 triggered at end of PWM period

  calcCPRDV();
  /*Serial.print("CPRDV = ");
  Serial.print(CPRDV);
  Serial.print("\n");*/
  PWM->PWM_CH_NUM[0].PWM_CPRD = CPRDV;                // Channel 0 Period f = 2MHz/(CPRD)= 100Hz = 0.01s |CPRD = 2MHz/f
  PWM->PWM_CH_NUM[0].PWM_CMR = PWM_CMR_CPRE_CLKA | PWM_CMR_DTE;     // Period is left aligned,clock source is CLKA on Channel 0
  PWM->PWM_CH_NUM[1].PWM_CMR = PWM_CMR_DTE;
  PWM->PWM_CH_NUM[2].PWM_CMR = PWM_CMR_DTE;

  //PWM->PWM_CH_NUM[0].PWM_DT = PWM_DT_DTH(0)| PWM_DT_DTL(200);
  //PWM->PWM_CH_NUM[1].PWM_DT = PWM_DT_DTH(0)| PWM_DT_DTL(200);
  //PWM->PWM_CH_NUM[2].PWM_DT = PWM_DT_DTH(0)| PWM_DT_DTL(200);
  
  PWM->PWM_ENA = PWM_ENA_CHID0;                       // Enable synchronous PWM on Channel 0
}

void loop()
{
  
}

void PWM_Handler()                       // PWM Interrupt Service Routine (ISR)
{
  if (PWM->PWM_ISR1 & PWM_ISR1_CHID0)    // Check if an update condition has occured
  {       
    update_Duty_Cycle();                 // Update the duty cycles
  }
}

void calcCPRDV ()
{
  //inverterFrequency = 60;
  static float numOfVectors = 6;
  static float adMCKFreq = 84000000;
  static float timerFreq = (adMCKFreq/divA); //2MHz
  static float period = 1/inverterFrequency;
  static float Ts = period/numOfVectors;
  static float switchingFreq = 1/Ts;
  CPRDV = (timerFreq/(1*switchingFreq));
  /*Serial.print("Inverter Frequency = "); Serial.print(inverterFrequency);Serial.print("\n");
  Serial.print("Num of Vectors = "); Serial.print(numOfVectors); Serial.print("\n");
  Serial.print("Timer Freq = "); Serial.print(timerFreq); Serial.print("\n");
  Serial.print("Period = "); Serial.print(period, 8); Serial.print("\n");
  Serial.print("SSV Period = "); Serial.print(Ts, 8); Serial.print("\n");
  Serial.print("Switching Freq = "); Serial.print(switchingFreq); Serial.print("\n");*/

}

void update_Duty_Cycle()
{
  
  
    if(stateCount < 6)
    {
          PWM->PWM_CH_NUM[0].PWM_CDTYUPD = 0;
          PWM->PWM_CH_NUM[1].PWM_CDTYUPD = 0;
          PWM->PWM_CH_NUM[2].PWM_CDTYUPD = 0;
          stateCount++;
          /*Serial.print("Counter = ");
          Serial.print(stateCount); Serial.print("\n");*/
    }
    else
    {
  
      static byte count = 0;
      static float p = CPRDV;
      static float n = 0;
      //Serial.print("Sector = "); Serial.print(count); Serial.print("\n");
      switch(count)
        {
          case 0: //pnn = 100 => 012
            PWM->PWM_CH_NUM[0].PWM_DTUPD = PWM_DTUPD_DTHUPD(0)| PWM_DTUPD_DTLUPD(2);
            PWM->PWM_CH_NUM[1].PWM_DTUPD = PWM_DTUPD_DTHUPD(0)| PWM_DTUPD_DTLUPD(2);
            PWM->PWM_CH_NUM[2].PWM_DTUPD = PWM_DTUPD_DTHUPD(0)| PWM_DTUPD_DTLUPD(2);
            
            PWM->PWM_CH_NUM[0].PWM_CDTYUPD = p;
            PWM->PWM_CH_NUM[1].PWM_CDTYUPD = n;
            PWM->PWM_CH_NUM[2].PWM_CDTYUPD = n;
          break;
          case 1: //ppn = 110 => 012 
            PWM->PWM_CH_NUM[0].PWM_DTUPD = PWM_DTUPD_DTHUPD(0)| PWM_DTUPD_DTLUPD(2);
            PWM->PWM_CH_NUM[1].PWM_DTUPD = PWM_DTUPD_DTHUPD(0)| PWM_DTUPD_DTLUPD(2);
            PWM->PWM_CH_NUM[2].PWM_DTUPD = PWM_DTUPD_DTHUPD(0)| PWM_DTUPD_DTLUPD(2);
            
            PWM->PWM_CH_NUM[0].PWM_CDTYUPD = p;
            PWM->PWM_CH_NUM[1].PWM_CDTYUPD = p;
            PWM->PWM_CH_NUM[2].PWM_CDTYUPD = n;
          break;
          case 2: //npn = 010 => 012
            PWM->PWM_CH_NUM[0].PWM_DTUPD = PWM_DTUPD_DTHUPD(0)| PWM_DTUPD_DTLUPD(2);
            PWM->PWM_CH_NUM[1].PWM_DTUPD = PWM_DTUPD_DTHUPD(0)| PWM_DTUPD_DTLUPD(2);
            PWM->PWM_CH_NUM[2].PWM_DTUPD = PWM_DTUPD_DTHUPD(0)| PWM_DTUPD_DTLUPD(2);
            
            PWM->PWM_CH_NUM[0].PWM_CDTYUPD = n;
            PWM->PWM_CH_NUM[1].PWM_CDTYUPD = p;
            PWM->PWM_CH_NUM[2].PWM_CDTYUPD = n;
          break;
          case 3: //npp = 011 => 012
            PWM->PWM_CH_NUM[0].PWM_DTUPD = PWM_DTUPD_DTHUPD(0)| PWM_DTUPD_DTLUPD(2);
            PWM->PWM_CH_NUM[1].PWM_DTUPD = PWM_DTUPD_DTHUPD(0)| PWM_DTUPD_DTLUPD(2);
            PWM->PWM_CH_NUM[2].PWM_DTUPD = PWM_DTUPD_DTHUPD(0)| PWM_DTUPD_DTLUPD(2);
            
            PWM->PWM_CH_NUM[0].PWM_CDTYUPD = n;
            PWM->PWM_CH_NUM[1].PWM_CDTYUPD = p;
            PWM->PWM_CH_NUM[2].PWM_CDTYUPD = p;
          break;
          case 4: //nnp = 001 => 012
            PWM->PWM_CH_NUM[0].PWM_DTUPD = PWM_DTUPD_DTHUPD(0)| PWM_DTUPD_DTLUPD(2);
            PWM->PWM_CH_NUM[1].PWM_DTUPD = PWM_DTUPD_DTHUPD(0)| PWM_DTUPD_DTLUPD(2);
            PWM->PWM_CH_NUM[2].PWM_DTUPD = PWM_DTUPD_DTHUPD(0)| PWM_DTUPD_DTLUPD(2);
            
            PWM->PWM_CH_NUM[0].PWM_CDTYUPD = n;
            PWM->PWM_CH_NUM[1].PWM_CDTYUPD = n;
            PWM->PWM_CH_NUM[2].PWM_CDTYUPD = p;
          break;
          case 5: //pnp = 101 => 012
            PWM->PWM_CH_NUM[0].PWM_DTUPD = PWM_DTUPD_DTHUPD(0)| PWM_DTUPD_DTLUPD(2);
            PWM->PWM_CH_NUM[1].PWM_DTUPD = PWM_DTUPD_DTHUPD(0)| PWM_DTUPD_DTLUPD(2);
            PWM->PWM_CH_NUM[2].PWM_DTUPD = PWM_DTUPD_DTHUPD(0)| PWM_DTUPD_DTLUPD(2);
            
            PWM->PWM_CH_NUM[0].PWM_CDTYUPD = p;
            PWM->PWM_CH_NUM[1].PWM_CDTYUPD = n;
            PWM->PWM_CH_NUM[2].PWM_CDTYUPD = p;

          break;
          default:
          break;
        }
        count = (count + 1) % 6;


    }
}

Could it be that the UPDULOCK bit must be set in order to allow the dead time registers to be updated?

Any luck? I've tried everything I can think of, and it's not working.

MartinL, If I would like to set the period of the pwm from a function, but the function takes input from a keypad and then uses the value inputted by the keypad to choose a case in a switch, how would be the best way to go about doing that?

Hi,

To change the period of the signals just requires you to change the period PER registers for channel 0:

PWM->PWM_CH_NUM[0].PWM_CPRD = CPRDV;

As your PWM signals span across a number of PWM cycles, I imagine it would be easiest to place to insert this line is in your update_Duty_Cycle() function, specifically in the one of the 6 output states. This also ensures that any changes happen at the beginning of your state output cycle.

To select differing periods your keypad could set a variable either containing the period or that can be used to select a preset period in the update_Duty_Cycle() function. As the update_Duty_Cycle() function is called from within the PWM_Handler(), but set by the keypad from outside it, it will be necessary to declare the variable as "volatile":

volatile unsigned long periodValue;

So if I want to be able to set the period value before the program even starts with the first duty cycle value I should do something like at the top of my handler

if (x <1)
{
      setPeriod(); 
      x++
}

And in this set period function I include the code that would allow the keypad to set the value of the period? Adding it to the top of the handler ensures that it is executed before any switching starts

If it's done this way I'm guessing it will remain in the function as long as the person is setting the period value. But after that it'll never enter that loop again because x would be equal to 1. What you think?

Is there a way to set the period of the pwm before the program starts using they keypad? I don't want the pwm to start until I've set the period. See because it's an inverter I'm designing I need to input the frequency value before the PWM starts. It needs to be inputted from the keypad. I also need to display the supply frequency value during the operation of the inverter.

Is it possible to call a function in setup to set parameters for PWM like say period? I want to set parameters in the program using a keypad and LCD display where the LCD is prompting you to input a voltage, and based on this voltage value a frequency will be calculated for constant v/f control of an induction motor. this frequency value will then calculate a CPRD value and then load that into the CPRD register of the Due before the setup is exited. So basically I want to know if I set up the keypad and LCD in the setup before i enable the Channel counter and exit the step up, if i call a function that utilizes the keypad and LCD after they are initialized in the setup if I will be able to use the keypad and LCD.

Is it possible to enable the pwm on a channel outside of the setup() function?

PWM->PWM_ENA = PWM_ENA_CHID0;

In essence call this piece of code after the period values have been set in the function.

Is it possible to enable the pwm on a channel outside of the setup() function?

Yes it is. However, if you disable the PWM Controller peripheral, (without switching the pins back to GPIO), they'll go high impedance and start to float. In might be better keep the PWM Controller enabled and to have a seventh "reset" state that sets the duty-cycle of all the outputs to 0.

Is it possible to call a function in setup to set parameters for PWM like say period?

Yes, it's possible to run any code in the setup() portion of the sketch, but it will only be run once. If your user only needs enter the code at the beginning, then the keypad input can be done at this stage. This means that you only need to set the PWM Controller's period (CPRD) register at the start. Also, in this instance there's no need to use a "volatile unsigned long" global variable or modify the update_Duty_Cycle() function.

Regarding the code pattern, I'd do something along these lines:

// ... Global variables

void setup() {
  // ...
  // ... Read keypad input
  switch(keypadInput)
  {
    case 0: 
      PWM->PWM_CH_NUM[0].PWM_CPRD = 1000;      // Arbitary values
      break;
    case 1:
      PWM->PWM_CH_NUM[0].PWM_CPRD = 2000;  
      break;
    case 2:
      PWM->PWM_CH_NUM[0].PWM_CPRD = 3000;
      break;
    case 3:
      // ...
  }
  // ... continue with setup() ...
}

void loop() {
  // ... Main code loop  
}

void PWM_Handler() {
  // ...
  update_Duty_Cycle();
  // ...
}

void update_DutyCycle() {
  // ...
}

How would the read keypad part of the code look if I'm using "Keypad.h" because I tried to set it in the setup but it didn't work.

I need the code to be written such that it won't leave the function unless it receives an input from the keypad to set the values.