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

Thread: Complementary PWM with the Teensy-LC

  1. #1
    Junior Member
    Join Date
    Jan 2014
    Posts
    19

    Complementary PWM with the Teensy-LC

    I'm using the Teensy LC and I'm having trouble configuring the TPM0 for complementary output. It should be as easy as setting the ELSnB:ELSnA bits, in the TPMx_CnSC register, but I'm having no luck. The channel 1 of TPM0 seems stuck in "High-true pulses (clear Output on match, set Output on reload)" mode.

    Please take a look at my code below and help me see where I've gone wrong. Thanks!

    HTML Code:
    // Pin 34 - PTC1 - TPM0-CH0 - LC-22 - ALT4
    // Pin 35 - PRC2 - TPM0-CH1 - LC-23 - ALT4
    
    const int ledPin = 13;
    
    #define TPM_C 48000000          // peripheral clock, for calculation only
    int PWM_FREQ = 60000;           // PWM frequency [Hz]
    float dutyCycle = 0.25;
    
    void setup() {
    
      pinMode(ledPin, OUTPUT);
      init_TPM0(); 
      TPM0_C0V = getDutyPeriod();              // Pin22
      TPM0_C1V = getMOD() - getDutyPeriod();   // Pin23
      TPM0_SC  = 0x08;                         // enable timer clock
    }
    
    void loop() {
    
      digitalWrite(ledPin, HIGH);           // set the LED on  
      delay(1000);                          // wait a bit
      digitalWrite(ledPin, LOW);            // set the LED off
      delay(1000);                          // wait a bit
    
    }
    
    void init_TPM0(){
    
      TPM0_SC   = 0x00;             // disable timer clock
      TPM0_C0SC = 0x28;             // Edge-aligned PWM, MSnB:MSnA (10), ELSnB:ELSnA (10) 
      TPM0_C1SC = 0x24;             // Edge-aligned PWM, MSnB:MSnA (10), ELSnB:ELSnA (01)
      TPM0_MOD  = getMOD();         // Period register
      CORE_PIN22_CONFIG = PORT_PCR_MUX(4) | PORT_PCR_DSE | PORT_PCR_SRE;  //TPM0-CH0
      CORE_PIN23_CONFIG = PORT_PCR_MUX(4) | PORT_PCR_DSE | PORT_PCR_SRE;  //TPM0-CH1
    
    }
    int getMOD(){
      
      int MODULO = (TPM_C / PWM_FREQ);
      return MODULO; 
    }
    int getDutyPeriod(){
    
      int PWM =  (int) getMOD() * dutyCycle;
      return PWM;
    }
    The end application requires two channels of PWM, with variable frequency and duty-cycle. The falling edge of one channel must align with the rising edge of the complementary channel. I would configure the channel values as following:
    HTML Code:
      TPM0_C0V = getDutyPeriod();               
      TPM0_C1V = getMOD() - getDutyPeriod();
    I have this working using the Teensy 3 and FlexTimerModule, but hope to port it to the LowCost version of Teensy

  2. #2
    Senior Member+ manitou's Avatar
    Join Date
    Jan 2013
    Posts
    1,476
    The ref manual (31.3.4) says you must disable TPMx_CnSC (set it to 0) and "wait" before setting a new value, see
    http://shawnhymel.com/681/learning-t...input-capture/

    maybe
    Code:
    ...
      TPM0_C0SC = TPM0_C1SC = 0;
      delayMicroseconds(1);
      TPM0_C0SC = 0x28;             // Edge-aligned PWM, MSnB:MSnA (10), ELSnB:ELSnA (10) 
      TPM0_C1SC = 0x24;             // Edge-aligned PWM, MSnB:MSnA (10), ELSnB:ELSnA (01)
    ...
    Last edited by manitou; 12-04-2017 at 11:15 PM.

  3. #3
    Junior Member
    Join Date
    Jan 2014
    Posts
    19
    Thank you Manitou. That worked!

    I must of read that brief ten times and kept getting hung up on the, "this must be acknowledged in the TPM counter clock domain". I was trying all sorts of quackery.

    Thanks again.

Posting Permissions

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