Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 8 of 8

Thread: phase correct PWM

  1. #1

    phase correct PWM

    In real life I'm a university lecturer. I was recently 'asked' to supervise some power electronics labs on behalf of an absent colleague. The students are required to build a class D audio amplifier using a dsPIC & Microchip's 'dsPICDEM MC1H 3 phase high voltage power module'

    In essence, they need to read an analogue input & generate PWM outputs.

    I thought it might be interesting to try this with a Teensy 3.1, it looks as though Paul has almost done this for me already - the 'PassThrough' example for the audio card comes very close to what I want!

    However, rather than one PWM output per channel, I need two. We use two phases of the power module as a H bridge to drive a speaker. So I'd also like to generate a phase correct PWM output for the 'other' side of the bridge. Ideally, I'd like to manipulate this too so that a guard band can be produced to avoid simultaneous conduction in the upper & lower limbs of the bridge.

    I'm aware that a phase correct PWM library exists for the Arduino but I don't expect this to work with Teensy.

    I don't really have time to figure this out for myself so if anyone has a quick fix I'm all ears!

    Cheers

    Ian

  2. #2
    Senior Member Constantin's Avatar
    Join Date
    Nov 2012
    Location
    In the yard with a 17' Dia. Ferris Wheel
    Posts
    1,408
    I'm not familiar with these designs, but it seems that the most common solution is to use a inverter chip on the output. See figure 8 and 9 on this page, for a conceptual and one implementation example.
    Last edited by Constantin; 01-29-2014 at 06:39 PM.

  3. #3
    Thanks Constantin,
    An inverter is likely to produce huge transients in a real circuit when the upper & lower limbs of the bridge conduct simultaneously.
    A very nice class D amp based on a ATTiny is here: http://rdimitrov.twistedsanity.net/b...0D%20Amplifier
    It biasses the transistors with LEDs but I can't do that.

    Ian

  4. #4
    Senior Member
    Join Date
    Nov 2012
    Location
    Boston, MA, USA
    Posts
    1,106
    Quote Originally Posted by ian View Post
    I'm aware that a phase correct PWM library exists for the Arduino but I don't expect this to work with Teensy.
    It might or might not. Got a link to that library?

  5. #5
    Senior Member
    Join Date
    Sep 2013
    Location
    Sonoma County, CA
    Posts
    141
    If you're interested in going deeper into the micro controller hardware than just using arduino libraries, the flex timer module that is used for PWM has built in dead-time insertion and a mode that allows you to set one channel as the complement of another channel. It looks like it would be as simple as setting the COMBINE, COMP, and DTEN bits in the FTMx_COMBINE register for whichever pair of channels you want to use, and setting the FTMx_DEADTIME register to however long you want the dead time to be. That way you can set a single PWM value, and both your normal and inverted PWM signals will be generated automatically.

    Full disclosure: although I'm planning on using something similar for a project, I haven't actually implemented the complementary PWM stuff yet, so you may have to play around with it a little to get it to work (it's all in chapter 35 of the reference manual).

    Good luck!
    Last edited by whollender; 01-30-2014 at 12:33 AM.

  6. #6
    Junior Member
    Join Date
    Jan 2014
    Posts
    19
    Have you had any luck getting the complementary PWM working?

    I'm trying to setup a complementary output on channels 2 and 3 of FlexTimer0. This is my first try dabbling with the K20 hardware directly, so maybe I've missed something completely.

    From what I can tell, I only need to enable the FlexTimer features with FTMEN = 1, combine channels 2 & 3 with COMBINE1 = 1, and set CH3 as the compliment of CH2 with COMP1 = 1.

    The problem I'm having is when I set FTMEN=1, the PWM output stops completely. Even after initializing the COMBINE register, I get no output after setting FTMEN = 1. Has anyone done this and could give me some pointers?

    Code:
    Code:
    const int ledPin =  13;
    const int PWM_H = 9;     //  FTM0 - CH2
    const int PWM_L = 10;    //  FTM0 - CH3
    
    void setup()   {                
      pinMode(ledPin, OUTPUT);
      pinMode(PWM_H, OUTPUT);
      pinMode(PWM_L, OUTPUT);
    
      analogWriteFrequency(PWM_H, 6000); // PWM frequency is 6kHz
      analogWriteResolution(10);         // 10-bits of PWM resolution
    
      FTM0_MODE = 0x5;          // FTMEN = 1, enables FlexTimer features/registers
    //  FTM0_COMBINE = 0x0030;    // COMP1 = 1, ch3 is the inverse of ch2
                                // COMBINE1 = 1, combines ch2 & ch3
                                
      analogWrite(PWM_H, 500);
    }
    
    void loop()                     
    {
      digitalWrite(ledPin,!digitalRead(ledPin));
      delay(500);
    }

  7. #7
    Junior Member
    Join Date
    Jan 2014
    Posts
    19
    I've managed to get the complementary output working. The code is crude and not very portable, but it's a good starting point
    Code:
    /*
      This program tests the initialization of complementary output.  
      FlexTimer0 hardware is configured by directly writing to the registers
      CH2 and CH3 of FTM0 are used, corresponding to pins 9 and 10 of the Teensy3.0 
      PWM Frequency can be set using the #define.
      Dead-time is set for 1uS
    */
    
    const int ledPin =  13;
    const int PWM_H = 9;     //  FTM0 - CH2
    const int PWM_L = 10;    //  FTM0 - CH3
    
    #define TPM_C 48000000            // core clock, for calculation only
    #define PWM_FREQ 6000            //  PWM frequency [Hz]
    #define MODULO (TPM_C / PWM_FREQ) // calculation the modulo for FTM0
    
    int PWMvalue =0;
    bool countDir =1;
    
    void setup()   {                
      pinMode(ledPin, OUTPUT);
      init_FTM0();
    }
    
    void loop()                     
    {
      ////////////////////////////////////////////
      //Loop will sweep the dutycycle up and down
      ////////////////////////////////////////////
      if(PWMvalue<MODULO && countDir)PWMvalue+=100;
      else if(countDir)countDir =0;
      if(PWMvalue>200 && !countDir)PWMvalue-=100;
      else if(!countDir)countDir =1;
    
      FTM0_C3V = PWMvalue; 
      FTM0_SYNC |= 0x80;             // set PWM value update
      
      digitalWrite(ledPin,!digitalRead(ledPin));
      delay(50);
    }
    
    void init_FTM0(){
      
     FTM0_POL = 0;                  // Positive Polarity 
     FTM0_OUTMASK = 0xFF;           // Use mask to disable outputs
     FTM0_SC = 0x08;                // set system clock as source for FTM0
     FTM0_MOD = MODULO;             // Period register
     FTM0_CNTIN = 0;                // Counter initial value
     FTM0_COMBINE = 0x00003300;     // COMBINE=1, COMP=1, DTEN=1, SYNCEN=1
     FTM0_MODE = 0x01;              // Enable FTM0
     FTM0_SYNC = 0x02;              // PWM sync @ max loading point enable
     FTM0_DEADTIME = 0x80;          // DeadTimer prescale systemClk/4
     FTM0_DEADTIME |= 12;           // 1uS DeadTime, max of 63 counts of 48Mhz clock
     FTM0_C2V = 0;                  // Combine mode, pulse-width controlled by...
     FTM0_C3V = MODULO/2;           //   odd channel.
     FTM0_SYNC |= 0x80;             // set PWM value update
     FTM0_C2SC = 0x28;              // PWM output, edge aligned, positive signal
     FTM0_C3SC = 0x28;              // PWM output, edge aligned, positive signal
     
     CORE_PIN9_CONFIG = PORT_PCR_MUX(4) | PORT_PCR_DSE | PORT_PCR_SRE;    //config teensy output port pins
     CORE_PIN10_CONFIG = PORT_PCR_MUX(4) | PORT_PCR_DSE | PORT_PCR_SRE;   //config teensy output port pins
     
     FTM0_OUTMASK = 0x0;            // Turns on PWM output
     
     /*  To update the PWM duty cycle, 
         write MODULO value to the FTM0_CnV of the odd combined channels.
         then use "FTM0_SYNC |= 0x80" to set the software trigger.
     */
    }

  8. #8
    Excellent!

    I spent an hour or so looking at the manual & came away with no more than a headache!
    I conceded that I wasn't going to solve this in my lunch hour...
    I've had a play with your code (as well as I could with only one working scope probe!) & it seems fine!

    It's ironic that this takes two lines of code on an Arduino!

    Ian
    Last edited by ian; 03-25-2014 at 10:17 PM.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •