Due PWM channels synchronization problem

hii friends…

I thought of driving the three phase inverter gate pulses using the DUE micro controller PWM macrocell. For that purpose, initially I decided to synchronize the PWM channels for same channel period in all channels. I synchronized channels 0, 1, 2, 3 and 6 just to check the functionality of the module.

The idea for the application code which I attached below was to change the duty ratio of the channel outputs when the pin 13 logic state changes. Unfortunately the duty ratio is not changing for channel-0 but the for the remaining channels the duty ratio is changing.

// In this code example five PWM channels of the DUE controller are synchronized.
// The channels duty ratio can be updated synchronously. (As per given in the datasheet)

// pin 35          PWMH0    
// pin 37          PWMH1
// pin 39          PWMH2
// pin 41          PWMH3
// pin 45          PWMH6

// Polling variable
volatile uint32_t V = 0;

void setup() 
{
  // polling the pin in counter events
  pinMode(13,INPUT_PULLUP);
  
  // Initializing the PWM channels.
  pmc_enable_periph_clk(PWM_INTERFACE_ID);                                                // Enabling the master clock for the PWM module.
  REG_PWM_WPCR    = 0x50574DF0;                                                           // Disabling the write protection.
  // Connecting the channels output to the MCU pin
  REG_PIOC_PDR   |= PIO_ABSR_P3 | PIO_ABSR_P5 | PIO_ABSR_P7 | PIO_ABSR_P9 | PIO_ABSR_P18;
  REG_PIOC_ABSR  |= PIO_ABSR_P3 | PIO_ABSR_P5 | PIO_ABSR_P7 | PIO_ABSR_P9 | PIO_ABSR_P18;
  REG_PIOC_PUDR   = 0x0000FFFF;                                                           //  disabling the pull ups.
  
  // selecting the manual write of dutycycle and automatic update to sync channels 
  REG_PWM_SCM    |= (PWM_SCM_SYNC0)|(PWM_SCM_SYNC1)|((PWM_SCM_SYNC2))|(PWM_SCM_SYNC3)|(PWM_SCM_SYNC6)|(PWM_SCM_UPDM_MODE1);
  
  // Channel-0
  REG_PWM_CMR0    = PWM_CMR_CPRE_MCK;                                                     // Initializing the channel-0.
  REG_PWM_CPRD0   = PWM_CPRD_CPRD(8404);                                                  // PWM period is 100us approximately.
  REG_PWM_CDTY0   = PWM_CDTY_CDTY(500);

  REG_PWM_CMPM0   = PWM_CMPM_CEN;                                                         // enabling the comparision 0 in the PWM comparision unit. 
  REG_PWM_CMPV0   = PWM_CMPV_CV(2000);
  REG_PWM_IER2   |= PWM_IER2_CMPM0;                                                       // enabling the comparison 0 interrupt.

  REG_PWM_IER2   |= PWM_IER2_CMPM1;
  NVIC_EnableIRQ(PWM_IRQn);                                                               // enable the PWM macrocell Interrupts.
  REG_PWM_ENA     = 0x00000001;                                                           // Enabling the channel 0.
}

void loop() 
{
  // Do nothing.
}

void PWM_Handler(void)
{
  static uint32_t FLAG = 0;
  FLAG = REG_PWM_ISR2;
  if((FLAG)&(PWM_IER2_CMPM0))                                                              // Here the comparison 0 interrupt is executed
  {
    V = PIOB->PIO_PDSR;
    if(V & (1 << 27))
    {
      // Here set the d0,d1 and d2 as 1000 and remaining 8000 
      while((REG_PWM_ISR2) & (PWM_ISR2_WRDY))                                             // polling the ready flag.
      REG_PWM_CDTYUPD0  = PWM_CDTYUPD_CDTYUPD(4000);                                      // channel 0
      REG_PWM_CDTYUPD1  = PWM_CDTYUPD_CDTYUPD(1000);                                      // channel 1
      REG_PWM_CDTYUPD2  = PWM_CDTYUPD_CDTYUPD(1000);                                      // channel 2
      REG_PWM_CDTYUPD3  = PWM_CDTYUPD_CDTYUPD(8404);                                      // channel 3
      REG_PWM_CDTYUPD6  = PWM_CDTYUPD_CDTYUPD(8000);                                      // channel 6
    }
    else
    {
      // Here set the d0,d1 and d2 as 8000 and remaining 1000
      while((REG_PWM_ISR2) & (PWM_ISR2_WRDY))                                             // polling the ready flag.
      REG_PWM_CDTYUPD0  = PWM_CDTYUPD_CDTYUPD(8000);                                      // channel 0
      REG_PWM_CDTYUPD1  = PWM_CDTYUPD_CDTYUPD(3000);                                      // channel 1
      REG_PWM_CDTYUPD2  = PWM_CDTYUPD_CDTYUPD(8000);                                      // channel 2
      REG_PWM_CDTYUPD3  = PWM_CDTYUPD_CDTYUPD(0);                                         // channel 3
      REG_PWM_CDTYUPD6  = PWM_CDTYUPD_CDTYUPD(1000);                                      // channel 6
    }
  }
}

// The code is under test.
// The code is working partially

The explanation for this behavior will be appreciated. Thanks in advance

Heyyy

ard_newbie, MarkT if you are free. Can you suggest any solution for my problem.

Did you read page 985 of Sam3x datasheet ?

Hii
ard_newbie.

Just now solved the problem.

Actually their is syntax mistake in the while statement. I forget to give semicolon in the interrupt segment code for polling the ready flag. After keeping the colon the code is working fine.

Thanks for the reply. (If i am having any tech doubts I ask you. :slight_smile: :slight_smile: )

Hey friends.

I have developed one more file, which uses channels 0,1 and 2 for driving the three phase inverter. To drive the BLDC motor.

The three channels are synchronized. The selected update mode was 0. So every time I fill the duty cycle value and make the UPDLOCK bit high. for updating the registers for the next PWM period. The code is below. any body can use the file as the templete for Three phase inverter operation. :slight_smile:

// Aim of this code example is to use the PWM channels in sync mode to drive the BLDC motor.
// The idea is HIGH side ON and LOW side PWM mode of switching.
  
// The connection for the gate driver board is.
// pin 34          PWML0 -------> T4
// pin 35          PWMH0 -------> T1
// pin 36          PWML1 -------> T6
// pin 37          PWMH1 -------> T3
// pin 38          PWML2 -------> T2
// pin 39          PWMH2 -------> T5

// pin 25          Hu -- yellow
// pin 26          Hv -- green
// pin 27          Hw -- blue

// Macros for the Over ride register values.
#define T1_ON   0x00000001
#define T3_ON   0x00000002
#define T5_ON   0x00000004
 
//  have to initialize the polling variable
volatile uint32_t V = 0;

void setup() 
{
  pinMode(13,OUTPUT);
  // configuration of the hall sensor inputs signals.
  pmc_enable_periph_clk(ID_PIOD);
  PIOD->PIO_PER      = (PIO_PER_P0)|(PIO_PER_P1)|(PIO_PER_P2);                               // Enbling the PIOD control.
  PIOD->PIO_ODR      = 0xFFFFFFFF;                                                           // Disabling the output.
  PIOD->PIO_PUER     = 0x00000007;                                                           // Enabling the pullup resistors.
  PIOD->PIO_IFER     = (PIO_IFER_P0)|(PIO_IFER_P1)|(PIO_IFER_P2);
  
  // configuring the PWM macrocell for driving the inverter switches based on PWM handler.
  pmc_enable_periph_clk(PWM_INTERFACE_ID);

  // Disabling the write protection of the PWM channel registers.
  REG_PWM_WPCR    = 0x50574DF0;
  
  // connecting the channel outputs to the MCU pins.
  REG_PIOC_PDR   |= PIO_ABSR_P2 | PIO_ABSR_P3 | PIO_ABSR_P4 | PIO_ABSR_P5 | PIO_ABSR_P6 | PIO_ABSR_P7;
  REG_PIOC_ABSR  |= PIO_ABSR_P2 | PIO_ABSR_P3 | PIO_ABSR_P4 | PIO_ABSR_P5 | PIO_ABSR_P6 | PIO_ABSR_P7;
  REG_PIOC_PUDR   = 0x0000FFFF;

  // Synchronizing the PWM channels 0,1 and 2.
  REG_PWM_SCM    |= (PWM_SCM_SYNC0)|(PWM_SCM_SYNC1)|(PWM_SCM_SYNC2)|(PWM_SCM_UPDM_MODE0); // Here the duty cycle register is updated manually and the 
                                                                                          // channels are updated manually.
                                                                                           
  // initializing the channel zero for generating the event trigger for ADC peripheral.
  REG_PWM_CMR0    = PWM_CMR_CPRE_MCK;                                                     // Initializing the channel-0.
  REG_PWM_CPRD0   = PWM_CPRD_CPRD(8404);                                                  // PWM period is 100us approximately.
  REG_PWM_CDTY0   = PWM_CDTY_CDTY(0);

  REG_PWM_CMPM0   = PWM_CMPM_CEN;                                                         // PWM Comparison 0 Mode Register
 
  REG_PWM_CMPV0   = PWM_CMPV_CV(8000);                                                    // comparison value for the event happening.
                                                                                          // The comparision value should be less than the channel-0 period value.

  REG_PWM_IER2   |= (PWM_IER2_CMPM0);                                                     // Generates the PWM event comparision-0 based interrupt.
  NVIC_EnableIRQ(PWM_IRQn);

  // channel 1
  REG_PWM_CPRD1   = PWM_CPRD_CPRD(8404);
  REG_PWM_CDTY1   = PWM_CDTY_CDTY(0);
  // channel 2
  REG_PWM_CPRD2   = PWM_CPRD_CPRD(8404);
  REG_PWM_CDTY2   = PWM_CDTY_CDTY(0);

  // The high side switches are controlled by the Override value of corresponding channel.
  REG_PWM_OS      =  0x00000007;
  REG_PWM_OOV     =  0x00000000;
  // Starting the PWM channels
  REG_PWM_ENA     = 0x00000001;
  
}

void loop() 
{
//  delay(10);
//  digitalWrite(13,HIGH);
//  delay(10);
//  digitalWrite(13,LOW);
}


void PWM_Handler(void)
{
    //         Commutation event interrupt.
    //         1. Here we do interrupt based polling of Hall signals 
    static uint32_t FLAG1 = 0;
    FLAG1 = REG_PWM_ISR2;
  if((FLAG1)&(PWM_IER2_CMPM0))
  {
    V = ((0b0111)&(PIOD->PIO_PDSR));
    // Here the electronic commutation of the BLDC motor can be performed.
    switch (V)
    {
    case 0b0100:
    // for 001, T4 and T5 should be driven.
         REG_PWM_OOV    = T5_ON;
         REG_PWM_CDTYUPD0  = PWM_CDTYUPD_CDTYUPD(4000);                          // T4 PWM
         REG_PWM_CDTYUPD1  = PWM_CDTYUPD_CDTYUPD(0);                             // T6 OFF
         REG_PWM_CDTYUPD2  = PWM_CDTYUPD_CDTYUPD(0);                             // T2 OFF
         REG_PWM_SCUC      = PWM_SCUC_UPDULOCK;
    break;
    case 0b0010:
    // for 010, T2 and T3 should be driven.
         REG_PWM_OOV    = T3_ON;
         REG_PWM_CDTYUPD0  = PWM_CDTYUPD_CDTYUPD(0);                             // T4 OFF
         REG_PWM_CDTYUPD1  = PWM_CDTYUPD_CDTYUPD(0);                             // T6 OFF
         REG_PWM_CDTYUPD2  = PWM_CDTYUPD_CDTYUPD(4000);                          // T2 PWM
         REG_PWM_SCUC      = PWM_SCUC_UPDULOCK;
    break;
    case 0b0110:
    // for 011, T3 and T4 should be driven.
         REG_PWM_OOV    = T3_ON;
         REG_PWM_CDTYUPD0  = PWM_CDTYUPD_CDTYUPD(4000);                          // T4 PWM
         REG_PWM_CDTYUPD1  = PWM_CDTYUPD_CDTYUPD(0);                             // T6 OFF
         REG_PWM_CDTYUPD2  = PWM_CDTYUPD_CDTYUPD(0);                             // T2 OFF
         REG_PWM_SCUC      = PWM_SCUC_UPDULOCK;
    break;
    case 0b0001:
    // for 100, T6 and T1 should be driven.
         REG_PWM_OOV    = T1_ON;
         REG_PWM_CDTYUPD0  = PWM_CDTYUPD_CDTYUPD(0);                             // T4 OFF
         REG_PWM_CDTYUPD1  = PWM_CDTYUPD_CDTYUPD(4000);                          // T6 PWM
         REG_PWM_CDTYUPD2  = PWM_CDTYUPD_CDTYUPD(0);                             // T2 OFF
         REG_PWM_SCUC      = PWM_SCUC_UPDULOCK;
    break;
    case 0b0101:
    // for 101, T5 and T6 should be driven.
         REG_PWM_OOV    = T5_ON;
         REG_PWM_CDTYUPD0  = PWM_CDTYUPD_CDTYUPD(0);                             // T4 OFF
         REG_PWM_CDTYUPD1  = PWM_CDTYUPD_CDTYUPD(4000);                          // T6 PWM
         REG_PWM_CDTYUPD2  = PWM_CDTYUPD_CDTYUPD(0);                             // T2 OFF
         REG_PWM_SCUC      = PWM_SCUC_UPDULOCK;
    break;
    case 0b0011:
    // for 110, T1 and T2 should be driven.
         REG_PWM_OOV    = T1_ON;
         REG_PWM_CDTYUPD0  = PWM_CDTYUPD_CDTYUPD(0);                             // T4 OFF
         REG_PWM_CDTYUPD1  = PWM_CDTYUPD_CDTYUPD(0);                             // T6 OFF
         REG_PWM_CDTYUPD2  = PWM_CDTYUPD_CDTYUPD(4000);                          // T2 PWM
         REG_PWM_SCUC      = PWM_SCUC_UPDULOCK;
    break;
    default:
    // All the switches are OFF.
         REG_PWM_OOV    = 0x00000000;
         REG_PWM_CDTYUPD0  = PWM_CDTYUPD_CDTYUPD(0);                             // T4 OFF
         REG_PWM_CDTYUPD1  = PWM_CDTYUPD_CDTYUPD(0);                             // T6 OFF
         REG_PWM_CDTYUPD2  = PWM_CDTYUPD_CDTYUPD(0);                             // T2 OFF         
         REG_PWM_SCUC      = PWM_SCUC_UPDULOCK;
    break;
    }
  }
}