Complementary PWM with the Teensy-LC

Status
Not open for further replies.

jlewis184

Member
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:
// 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:
  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 :)
 
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-the-teensy-lc-input-capture/

maybe
Code:
...
 [B] TPM0_C0SC = TPM0_C1SC = 0;
  delayMicroseconds(1);[/B]
  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:
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.
 
Status
Not open for further replies.
Back
Top