Go Down

Topic: 100Khz Square Wave Created on 8 channels, but Having Problems Adding A Delay (Read 732 times) previous topic - next topic

williamstriker99

Oct 06, 2018, 12:45 am Last Edit: Oct 06, 2018, 04:30 am by surbyte Reason: Code tags added
Hi Everybody,

The Code confirmed working for Arduino Due. The Code Below creates 100Khz Square Wave Created on 8 channels, but Having Problems Adding A Delay.

I need to take one of the 8 channels (Like Pin A8), and simply make it 2 microseconds slower than the others.

Any Help would be Great Appreciated!!


Code Below:


Code: [Select]
// Enable single slope, 11-bit resolution PWM at 40kHz on 8 channels
void setup() {
 // PWM set-up on pins DAC1, A8, A9, A10, D9, D8, D7 and D6 for channels 0 through to 7 respectively
 REG_PMC_PCER1 |= PMC_PCER1_PID36;                                               // Enable PWM
 REG_PIOB_ABSR |= PIO_ABSR_P19 | PIO_ABSR_P18 | PIO_ABSR_P17 | PIO_ABSR_P16;     // Set the port B PWM pins to peripheral type B
 REG_PIOC_ABSR |= PIO_ABSR_P24 | PIO_ABSR_P23 | PIO_ABSR_P22 | PIO_ABSR_P21;     // Set the port C PWM pins to peripheral type B
 REG_PIOB_PDR |= PIO_PDR_P19 | PIO_PDR_P18 | PIO_PDR_P17 | PIO_PDR_P16;          // Set the port B PWM pins to outputs
 REG_PIOC_PDR |= PIO_PDR_P24 | PIO_PDR_P23 | PIO_PDR_P22 | PIO_PDR_P21;          // Set the port C PWM pins to outputs
 REG_PWM_CLK = PWM_CLK_PREA(0) | PWM_CLK_DIVA(1);                                // Set the PWM clock A rate to 84MHz (84MHz/1)
 //REG_PWM_SCM |= PWM_SCM_SYNC7 | PWM_SCM_SYNC6 | PWM_SCM_SYNC5 | PWM_SCM_SYNC4 |  // Set the PWM channels as synchronous
 //               PWM_SCM_SYNC3 | PWM_SCM_SYNC2 | PWM_SCM_SYNC1 | PWM_SCM_SYNC0;  
 for (uint8_t i = 0; i < PWMCH_NUM_NUMBER; i++)                      // Loop for each PWM channel (8 in total)
 {
   PWM->PWM_CH_NUM[i].PWM_CMR =  PWM_CMR_CPRE_CLKA;                  // Enable single slope PWM and set the clock source as CLKA
   PWM->PWM_CH_NUM[i].PWM_CPRD = 840;                               // Set the PWM period register 84MHz/(.1MHz)=840;
 }
 //REG_PWM_ENA = PWM_ENA_CHID0;           // Enable the PWM channels, (only need to set channel 0 for synchronous mode)
 REG_PWM_ENA = PWM_ENA_CHID7 | PWM_ENA_CHID6 | PWM_ENA_CHID5 | PWM_ENA_CHID4 |    // Enable all PWM channels
               PWM_ENA_CHID3 | PWM_ENA_CHID2 | PWM_ENA_CHID1 | PWM_ENA_CHID0;
 for (uint8_t i = 0; i < PWMCH_NUM_NUMBER; i++)                      // Loop for each PWM channel (8 in total)
 {
   PWM->PWM_CH_NUM[i].PWM_CDTYUPD = 420;                            // Set the PWM duty cycle to 50% (2100/2=1050) on all channels
 }
 //REG_PWM_SCUC = PWM_SCUC_UPDULOCK;      // Set the update unlock bit to trigger an update at the end of the next PWM period
}


void loop() {
 REG_PMC_PCER1 |= PMC_PCER1_PID36;                     // Enable PWM
 REG_PIOB_ABSR |= PIO_ABSR_P16;                        // Set PWM pin perhipheral type A or B, in this case B
 REG_PIOB_PDR |= PIO_PDR_P16;                          // Set PWM pin to an output
 REG_PWM_CLK = PWM_CLK_PREA(0) | PWM_CLK_DIVA(1);      // Set the PWM clock rate to 84MHz (84MHz/1)
 REG_PWM_CMR0 = PWM_CMR_CPRE_CLKA;                     // Enable single slope PWM and set the clock source as CLKA
 REG_PWM_CPRD0 = 840;                                   // Set the PWM frequency 84MHz/.1MHz = 840
 REG_PWM_CDTY0 = 420;                                   // Set the PWM duty cycle 50%\
 REG_PWM_ENA = PWM_ENA_CHID0;                          // Enable the PWM channel
 }


Please let me know if anyone knows how to do this.

Thanks,

- Bill

ard_newbie

There are several issues in your code:

- You don't need to enable PWM at each beginning of the loop(), only once in setup() is correct,
- When you are in loop() and the PWM has been previously enabled in setup(), you can modify CPRD and CDTY of a PWM channel with CPRDUPD (CPRD Up Date) and CDTYUPD so that they are updated at the beginning of a new PWM period (plus see UPDULOCK bit).

An example sketch with a single PWM channel:

Code: [Select]

/******************************************************************************/
/*                         PWMH0 640 Hz                                        */
/******************************************************************************/

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);

  PMC->PMC_PCER1 |= PMC_PCER1_PID36;                   // PWM power ON

  PIOC->PIO_PDR |= PIO_PDR_P3;                         // Set PWM pin to a peripheral
  PIOC->PIO_ABSR |= PIO_PC3B_PWMH0;                    // Set PWM pin peripheral type B for PWMH0 (Arduino pin 35)

  PWM->PWM_CLK = PWM_CLK_PREB(0) | PWM_CLK_DIVB(2);    // select Frequency for clock B: Mck/2 = 42 MHz

  PWM->PWM_CH_NUM[0].PWM_CMR = PWM_CMR_CPRE_CLKB;      // The period is left aligned, clock source as CLKB on channel 0
  PWM->PWM_CH_NUM[0].PWM_CPRD = 65535;                 // Set the PWM frequency 42 MHz/PWM_CPRD = 640 Hz
  PWM->PWM_CH_NUM[0].PWM_CDTY = 32768;                 // Set the PWM duty cycle = (CDTY/CPRD) * 100 %

  PWM->PWM_IER1 = PWM_IER1_CHID0;                      // Interrupt on PWM Channel 0 counter
  NVIC_EnableIRQ(PWM_IRQn);                            // Enable interrupt

  PWM->PWM_ENA = PWM_ENA_CHID0;                        // Enable PWM channel 0
}

void loop() {

}

void PWM_Handler() {
  static uint32_t Count;
  static boolean Flag;
  PWM->PWM_ISR1;      // Clear status register
  if (Count++ == 640) {
    PIOB->PIO_ODSR ^= PIO_ODSR_P27;

    Count = 0;
  }
}


williamstriker99

ard_newbie, I think I understand your code, but I'm trying to add a delay to say Arduino due output pin A8. So the Square wave out of A8 is 1.6 Microseconds slower than the other 7 square waves.

Let me know what you think... I've been working on this for a few weeks with no progress

ard_newbie


It's unclear what you mean by: the square wave out of A8 is 1.6 Microseconds slower than the other 7 square waves. If you mean PWML1 (pin A8 is PB17 for PWML1, Sam3x datasheet page 974) has the same frequency than the 7 other PWM signals but starts 1.6 Microseconds later, then enable Channel 1 1.6 Microseconds later with PWM->PWM_ENA = PWM_ENA_CHID1; ,if you mean PWML1 has a longer period than the 7 others, adjust CPRD and CDTY for this particular channel.

williamstriker99

ard_newbie, That is exactly what I am asking about. I just want pin a8 out of my 8 output pins to start 1.6 microseconds later. How should I edit my code?


CODE:

// Enable single slope, 11-bit resolution PWM at 40kHz on 8 channels
void setup() {
  // PWM set-up on pins DAC1, A8, A9, A10, D9, D8, D7 and D6 for channels 0 through to 7 respectively
  REG_PMC_PCER1 |= PMC_PCER1_PID36;                                               // Enable PWM
  REG_PIOB_ABSR |= PIO_ABSR_P19 | PIO_ABSR_P18 | PIO_ABSR_P17 | PIO_ABSR_P16;     // Set the port B PWM pins to peripheral type B
  REG_PIOC_ABSR |= PIO_ABSR_P24 | PIO_ABSR_P23 | PIO_ABSR_P22 | PIO_ABSR_P21;     // Set the port C PWM pins to peripheral type B
  REG_PIOB_PDR |= PIO_PDR_P19 | PIO_PDR_P18 | PIO_PDR_P17 | PIO_PDR_P16;          // Set the port B PWM pins to outputs
  REG_PIOC_PDR |= PIO_PDR_P24 | PIO_PDR_P23 | PIO_PDR_P22 | PIO_PDR_P21;          // Set the port C PWM pins to outputs
  REG_PWM_CLK = PWM_CLK_PREA(0) | PWM_CLK_DIVA(1);                                // Set the PWM clock A rate to 84MHz (84MHz/1)
  //REG_PWM_SCM |= PWM_SCM_SYNC7 | PWM_SCM_SYNC6 | PWM_SCM_SYNC5 | PWM_SCM_SYNC4 |  // Set the PWM channels as synchronous
  //               PWM_SCM_SYNC3 | PWM_SCM_SYNC2 | PWM_SCM_SYNC1 | PWM_SCM_SYNC0; 
  for (uint8_t i = 0; i < PWMCH_NUM_NUMBER; i++)                      // Loop for each PWM channel (8 in total)
  {
    PWM->PWM_CH_NUM.PWM_CMR =  PWM_CMR_CPRE_CLKA;                  // Enable single slope PWM and set the clock source as CLKA
    PWM->PWM_CH_NUM.PWM_CPRD = 840;                               // Set the PWM period register 84MHz/(.1MHz)=840;
  }
  //REG_PWM_ENA = PWM_ENA_CHID0;           // Enable the PWM channels, (only need to set channel 0 for synchronous mode)
  REG_PWM_ENA = PWM_ENA_CHID7 | PWM_ENA_CHID6 | PWM_ENA_CHID5 | PWM_ENA_CHID4 |    // Enable all PWM channels
                PWM_ENA_CHID3 | PWM_ENA_CHID2 | PWM_ENA_CHID1 | PWM_ENA_CHID0;
  for (uint8_t i = 0; i < PWMCH_NUM_NUMBER; i++)                      // Loop for each PWM channel (8 in total)
  {
    PWM->PWM_CH_NUM.PWM_CDTYUPD = 420;                            // Set the PWM duty cycle to 50% (2100/2=1050) on all channels
  }
  //REG_PWM_SCUC = PWM_SCUC_UPDULOCK;      // Set the update unlock bit to trigger an update at the end of the next PWM period
}


MartinL

To delay one PWM output channel by 2us with respect to the others, it's necessary to use dead-time insertion.

The PWM channels are set as synchronous, so that they're aligned with one another. The synchronous channels' control mode (PWM_CMRx) and period (PWM_CPRDx) registers are then accessed through channel 0 (PWM_CMR0 and PWM_CPRD0). However, the dead-time enable (DTE) bit is set in channels 7's control mode register (PWM_CMR7), (in this example channel 7's being delayed, but any channel could be used).

The delay time itself is set by channel 7's dead-time register (PWM_DT). As the channel 7's output on D6 is named "PWML7" it's a low side (rather than a high side) output, therefore it's necessary to set the low side dead-time (PWM_DT_DTL) portion of this register.

The 100kHz PWM output has a period of 10us, therefore 2us is 1/5th of the period, so the PWM_DT_DTL is set to 167, (839 * 0.2). This delays the signal's leading high edge by 2us with respect to the other channels. To move the low going edge back by the same amount it's necessary to add the 167 to 419 in the channel 7's duty cyle register (PWM_CDTY7).

The code below delays PWM channel 7 (PWML7) on D6, by 2us with respect to the other channels, at 100kHz and 50% duty cycle:

Code: [Select]
// Enable synchronous, single-slope PWM at 100kHz on 8 channels, channel 7 delayed by 2us
void setup() {
  // PWM set-up on pins DAC1, A8, A9, A10, D9, D8, D7 and D6 for channels 0 through to 7 respectively
  PMC->PMC_PCER1 |= PMC_PCER1_PID36;                                               // Enable PWM
  PIOB->PIO_ABSR |= PIO_ABSR_P19 | PIO_ABSR_P18 | PIO_ABSR_P17 | PIO_ABSR_P16;     // Set the port B PWM pins to peripheral type B
  PIOC->PIO_ABSR |= PIO_ABSR_P24 | PIO_ABSR_P23 | PIO_ABSR_P22 | PIO_ABSR_P21;     // Set the port C PWM pins to peripheral type B
  PIOB->PIO_PDR |= PIO_PDR_P19 | PIO_PDR_P18 | PIO_PDR_P17 | PIO_PDR_P16;          // Set the port B PWM pins to outputs
  PIOC->PIO_PDR |= PIO_PDR_P24 | PIO_PDR_P23 | PIO_PDR_P22 | PIO_PDR_P21;          // Set the port C PWM pins to outputs
  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_SYNC7 | PWM_SCM_SYNC6 | PWM_SCM_SYNC5 | PWM_SCM_SYNC4 |  // Set the PWM channels as synchronous
                  PWM_SCM_SYNC3 | PWM_SCM_SYNC2 | PWM_SCM_SYNC1 | PWM_SCM_SYNC0;
  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 = 839;                   // Set the PWM frequency 84MHz/(839 + 1) = 100kHz for all synchronous channels
  for (uint8_t i = 0; i < PWMCH_NUM_NUMBER; i++)       // Loop for each PWM channel (8 in total)
  {
    PWM->PWM_CH_NUM[i].PWM_CDTY = 419;                 // Set the PWM duty cycle to 50%
  }
  PWM->PWM_CH_NUM[7].PWM_CMR = PWM_CMR_DTE | PWM_CMR_CPRE_CLKA;   // Enable single slope PWM and set the clock source as CLKA for all synchronous channels
  PWM->PWM_CH_NUM[7].PWM_DT = PWM_DT_DTH(0) | PWM_DT_DTL(167);    // Set the low and high dead-time for 2us delay (100kHz => 10us period)
  PWM->PWM_CH_NUM[7].PWM_CDTY = 419 + 167;                        // Set the PWM duty cycle to 50%
  PWM->PWM_ENA = PWM_ENA_CHID7 | PWM_ENA_CHID6 | PWM_ENA_CHID5 | PWM_ENA_CHID4 |  // Enable all PWM channels
                 PWM_ENA_CHID3 | PWM_ENA_CHID2 | PWM_ENA_CHID1 | PWM_ENA_CHID0;
  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() {}

williamstriker99

 
Thanks MartinL, I will try it tomorrow and let you guys know how it goes.

How did you figure out that Channel 7 (PWML7) could be connected to D6? Are there docs or links for Cross-referencing data for this?

I am asking because I would like to run your code with the addition of having an inversed DC Square Wave on D7, with the delayed DC Square Wave on D6, and a non-inversed regular DC Square Wave on the other 5 Arduino Due Outputs.

Thanks for your help: Teaching a guy how to fish.

- Bill

 

MartinL

Hi Bill,

It's possible to cross-reference the port pin to Arduino pin using the Arduino Due schematic diagram and the PIO Controller Multiplexing table in the SAM3X8E datasheet.

The example code above uses all the low side, PWMLx outputs: PWML0...PWML7, which correspond to the Due pins: DAC1, A8, A9, A10, D9, D8, D7 and D6 respectively.

The channel polarity can be changed by setting the channel polarity (CPOL) bit in the given PWM channel's Channel Mode Register (PWM_CMR):

Code: [Select]
PWM->PWM_CH_NUM[4].PWM_CMR |= PWM_CMR_CPOL;
or if dead-time is enabled for the channel, using dead-time output inversion bit (PWM_DTLI):

Code: [Select]
PWM->PWM_CH_NUM[4].PWM_CMR |= PWM_CMR_DTLI;
There is one caveat regarding the above code, in that inserting a 20% (2us) dead-time results in a maximum 80% duty-cycle, (as the delayed signal can't overlap the end of the timer period), but if you're working with square waves with 50% duty-cycle then it should work just fine.

williamstriker99

I need to add a delay to 4 channels, like DAC1, D8, D7 and D6 , is this possible? and with my set-up which pins should i use to do which things? I am not familiar with the actual processor so I do not know.

MartinL

Quote
I need to add a delay to 4 channels, like DAC1, D8, D7 and D6 , is this possible?
Yes, here's the code that delays channels DAC1, D8, D7 and D6 by 2us with respect the remaining 4 channels (A10, A9, A8 and D9):

Code: [Select]
// Enable synchronous, single-slope PWM at 100kHz on 8 channels, channels 0, 5, 6 and 7 delayed by 2us
void setup() {
  // PWM set-up on pins DAC1, A8, A9, A10, D9, D8, D7 and D6 for channels 0 through to 7 respectively
  PMC->PMC_PCER1 |= PMC_PCER1_PID36;                                               // Enable PWM
  PIOB->PIO_ABSR |= PIO_ABSR_P19 | PIO_ABSR_P18 | PIO_ABSR_P17 | PIO_ABSR_P16;     // Set the port B PWM pins to peripheral type B
  PIOC->PIO_ABSR |= PIO_ABSR_P24 | PIO_ABSR_P23 | PIO_ABSR_P22 | PIO_ABSR_P21;     // Set the port C PWM pins to peripheral type B
  PIOB->PIO_PDR |= PIO_PDR_P19 | PIO_PDR_P18 | PIO_PDR_P17 | PIO_PDR_P16;          // Set the port B PWM pins to outputs
  PIOC->PIO_PDR |= PIO_PDR_P24 | PIO_PDR_P23 | PIO_PDR_P22 | PIO_PDR_P21;          // Set the port C PWM pins to outputs
  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_SYNC7 | PWM_SCM_SYNC6 | PWM_SCM_SYNC5 | PWM_SCM_SYNC4 |  // Set the PWM channels as synchronous
                  PWM_SCM_SYNC3 | PWM_SCM_SYNC2 | PWM_SCM_SYNC1 | PWM_SCM_SYNC0;
  //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 = 839;                   // Set the PWM frequency 84MHz/(839 + 1) = 100kHz for all synchronous channels
  for (uint8_t i = 0; i < PWMCH_NUM_NUMBER; i++)       // Loop for each PWM channel (8 in total)
  {
    PWM->PWM_CH_NUM[i].PWM_CDTY = 419;                 // Set the PWM duty cycle to 50%
  }
  uint8_t channels[] = { 0, 5, 6, 7 };                 // Specify the delayed channels
  for (uint8_t i = 0; i < sizeof(channels); i++)       // Iterate through each of the delayed channels
  {
    PWM->PWM_CH_NUM[channels[i]].PWM_CMR = PWM_CMR_DTE | PWM_CMR_CPRE_CLKA;   // Enable single slope PWM and set the clock source as CLKA for all synchronous channels
    PWM->PWM_CH_NUM[channels[i]].PWM_DT = PWM_DT_DTH(0) | PWM_DT_DTL(167);    // Set the low dead-time for 2us delay (100kHz => 10us period)
    PWM->PWM_CH_NUM[channels[i]].PWM_CDTY = 419 + 167;                        // Set the PWM duty cycle to 50%
  }      
  PWM->PWM_ENA = PWM_ENA_CHID7 | PWM_ENA_CHID6 | PWM_ENA_CHID5 | PWM_ENA_CHID4 |  // Enable all PWM channels
                 PWM_ENA_CHID3 | PWM_ENA_CHID2 | PWM_ENA_CHID1 | PWM_ENA_CHID0;
  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() {}

williamstriker99

MartinL,

Do you know if it is possible to add a nanosecond delay instead of a microsecond delay?

williamstriker99

Also,

How can I add, to the code you posted last, A 10 MicroSecond Delay to Channel 1, And a 4 MicroSecond Delay to Channel 2?

williamstriker99

Hi Everybody,

I am trying to add a 1000 Nanosecond Delay to one of these below 8 channel square waves. (I have only been able to successfully do this to the MicroSecond Increment So Far)
Project Name: 100kHz on 8 channels, channels 0, 5, 6 and 7 delayed by 2 MicroSeconds

Please let me know if anyone knows how to do this!
I am open to changing the code, as long as there is 1 channel that has a regular square wave, and 1 channel that has the same regular square wave but with a 1000 Nanosecond Delay.

Code Below:

// Enable synchronous, single-slope PWM at 100kHz on 8 channels, channels 0, 5, 6 and 7 delayed by 2us
void setup() {
  // PWM set-up on pins DAC1, A8, A9, A10, D9, D8, D7 and D6 for channels 0 through to 7 respectively
  PMC->PMC_PCER1 |= PMC_PCER1_PID36;                                               // Enable PWM
  PIOB->PIO_ABSR |= PIO_ABSR_P19 | PIO_ABSR_P18 | PIO_ABSR_P17 | PIO_ABSR_P16;     // Set the port B PWM pins to peripheral type B
  PIOC->PIO_ABSR |= PIO_ABSR_P24 | PIO_ABSR_P23 | PIO_ABSR_P22 | PIO_ABSR_P21;     // Set the port C PWM pins to peripheral type B
  PIOB->PIO_PDR |= PIO_PDR_P19 | PIO_PDR_P18 | PIO_PDR_P17 | PIO_PDR_P16;          // Set the port B PWM pins to outputs
  PIOC->PIO_PDR |= PIO_PDR_P24 | PIO_PDR_P23 | PIO_PDR_P22 | PIO_PDR_P21;          // Set the port C PWM pins to outputs
  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_SYNC7 | PWM_SCM_SYNC6 | PWM_SCM_SYNC5 | PWM_SCM_SYNC4 |  // Set the PWM channels as synchronous
                  PWM_SCM_SYNC3 | PWM_SCM_SYNC2 | PWM_SCM_SYNC1 | PWM_SCM_SYNC0;
  //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 = 839;                   // Set the PWM frequency 84MHz/(839 + 1) = 100kHz for all synchronous channels
  for (uint8_t i = 0; i < PWMCH_NUM_NUMBER; i++)       // Loop for each PWM channel (8 in total)
  {
    PWM->PWM_CH_NUM.PWM_CDTY = 419;                 // Set the PWM duty cycle to 50%
  }
  uint8_t channels[] = {  5, 6, 7 };                 // Specify the delayed channels
  for (uint8_t i = 0; i < sizeof(channels); i++)       // Iterate through each of the delayed channels
  {
    PWM->PWM_CH_NUM[channels].PWM_CMR = PWM_CMR_DTE | PWM_CMR_CPRE_CLKA;   // Enable single slope PWM and set the clock source as CLKA for all synchronous channels
    PWM->PWM_CH_NUM[channels].PWM_DT = PWM_DT_DTH(0) | PWM_DT_DTL(167);    // Set the low dead-time for 2us delay (100kHz => 10us period)
    PWM->PWM_CH_NUM[channels].PWM_CDTY = 419 + 167;                        // Set the PWM duty cycle to 50%
  }       
  PWM->PWM_ENA = PWM_ENA_CHID7 | PWM_ENA_CHID6 | PWM_ENA_CHID5 | PWM_ENA_CHID4 |  // Enable all PWM channels
                 PWM_ENA_CHID3 | PWM_ENA_CHID2 | PWM_ENA_CHID1 | PWM_ENA_CHID0;
  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() {}

Coding Badly


@williamstriker99, please do not cross-post.  Threads merged.


MartinL

Hi Bill,

The 8 PWM timers are running at 100kHz for each channel, that's a 10us period (1/100kHz). This period takes 840 timer ticks to complete and each tick takes about 11.9ns (10us / 840).

The dead-time period is just 11.9ns * (167 + 1) = 2us delay, therefore to adjust the dead-time delay to say 1us, just change the dead-time period in the PWM_DT registers for the given channel to 83 (1us/11.9ns - 1).

For example, to change the delay on channels 1, 2 and 3 to 1us, 2us and 4us respectively:

Code: [Select]
// Enable synchronous, single-slope PWM at 100kHz on 8 channels, channels 1, 2 and 3 delayed by 1us, 2us and 4us respectively
void setup() {
  // PWM set-up on pins DAC1, A8, A9, A10, D9, D8, D7 and D6 for channels 0 through to 7 respectively
  PMC->PMC_PCER1 |= PMC_PCER1_PID36;                                               // Enable PWM
  PIOB->PIO_ABSR |= PIO_ABSR_P19 | PIO_ABSR_P18 | PIO_ABSR_P17 | PIO_ABSR_P16;     // Set the port B PWM pins to peripheral type B
  PIOC->PIO_ABSR |= PIO_ABSR_P24 | PIO_ABSR_P23 | PIO_ABSR_P22 | PIO_ABSR_P21;     // Set the port C PWM pins to peripheral type B
  PIOB->PIO_PDR |= PIO_PDR_P19 | PIO_PDR_P18 | PIO_PDR_P17 | PIO_PDR_P16;          // Set the port B PWM pins to outputs
  PIOC->PIO_PDR |= PIO_PDR_P24 | PIO_PDR_P23 | PIO_PDR_P22 | PIO_PDR_P21;          // Set the port C PWM pins to outputs
  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_SYNC7 | PWM_SCM_SYNC6 | PWM_SCM_SYNC5 | PWM_SCM_SYNC4 |  // Set the PWM channels as synchronous
                  PWM_SCM_SYNC3 | PWM_SCM_SYNC2 | PWM_SCM_SYNC1 | PWM_SCM_SYNC0;
  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 = 839;                   // Set the PWM frequency 84MHz/(839 + 1) = 100kHz for all synchronous channels
  for (uint8_t i = 0; i < PWMCH_NUM_NUMBER; i++)       // Loop for each PWM channel (8 in total)
  {
    PWM->PWM_CH_NUM[i].PWM_CDTY = 419;                 // Set the PWM duty cycle to 50%
  }
 
  // Channel 1 - 1us delay
  PWM->PWM_CH_NUM[1].PWM_CMR = PWM_CMR_DTE | PWM_CMR_CPRE_CLKA;   // Enable single slope PWM and set the clock source as CLKA
  PWM->PWM_CH_NUM[1].PWM_DT = PWM_DT_DTH(0) | PWM_DT_DTL(83);    // Set the low dead-time for 1us delay (100kHz => 10us period)
  PWM->PWM_CH_NUM[1].PWM_CDTY = 419 + 83;                        // Set the PWM duty cycle to 50%PWM->PWM_CH_NUM[channels[i]].PWM_CMR = PWM_CMR_DTE | PWM_CMR_CPRE_CLKA;

  // Channel 2 - 2us delay
  PWM->PWM_CH_NUM[2].PWM_CMR = PWM_CMR_DTE | PWM_CMR_CPRE_CLKA;   // Enable single slope PWM and set the clock source as CLKA
  PWM->PWM_CH_NUM[2].PWM_DT = PWM_DT_DTH(0) | PWM_DT_DTL(167);    // Set the low dead-time for 2us delay (100kHz => 10us period)
  PWM->PWM_CH_NUM[2].PWM_CDTY = 419 + 167;                        // Set the PWM duty cycle to 50%

  // Channel 3 - 4us delay
  PWM->PWM_CH_NUM[3].PWM_CMR = PWM_CMR_DTE | PWM_CMR_CPRE_CLKA;   // Enable single slope PWM and set the clock source as CLKA
  PWM->PWM_CH_NUM[3].PWM_DT = PWM_DT_DTH(0) | PWM_DT_DTL(335);    // Set the low dead-time for 4us delay (100kHz => 10us period)
  PWM->PWM_CH_NUM[3].PWM_CDTY = 419 + 335;                        // Set the PWM duty cycle to 50%
     
  PWM->PWM_ENA = PWM_ENA_CHID7 | PWM_ENA_CHID6 | PWM_ENA_CHID5 | PWM_ENA_CHID4 |  // Enable all PWM channels
                 PWM_ENA_CHID3 | PWM_ENA_CHID2 | PWM_ENA_CHID1 | PWM_ENA_CHID0;
  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() {}

Go Up