Hi,
I'm seeing some odd behavior with the high resolution Timer D generating 2 center aligned PWM signals with varying dead time.
The PWM frequency is 132kHz, and the min and max duty are such that it does not enter the "not recommended" minimum on time.
I have an interrupt that increases the CCR register by one count every second. This is latched at TDR=0, so the PWM updates without glitching.
Observation 1: Instead of seeing the duty cycle increase by the expected ~16ns per second, it increases by 125ns every eight seconds.
Observation 2: When I look at both signals at once, for the 7 second intervals where the duty cycle remains unchanged, one PWM signal marches forward by ~16ns, only to reset to its starting position with the now increased by 125ns duty cycle on the 8th second.
Question: Is this possibly something I've configured wrong or is there a hidden/undocumented feature here that I've stumbled upon?
I've included the pwm setup routine and duty cycle update routine:
Edward
I'm running off a 32k768Hz crystal, using the DCO/FLL to generate a 16MHz SMCLK, which is used as the source for TimerD0 hi freq generator which is locked on at 8x to make 128MHz timer clock.
void configure_pwm(void)
{
//reset timer counts and direction:
TD0CTL0 = TDCLR;
TD0HCTL0 = 0; // kill the clock if it is still running
TD0HINT &= ~TDHLKIFG; // clear FLL lock Flag
//setup TimerD0 High speed clock
TD0HCTL1 = TDHCLKCR; // input is greater than 15Mhz
TD0CTL0 = TDSSEL_2; // set the input clock for the FLL to sync to.
TD0HCTL0 = //TDHFW | // Fast Wakeup?
TDHD_0 | // divider _0: /1 _1: /2 _2: /4 _3: /8
TDHM_0 | // multiplier _0: x8 _1: x16
TDHRON | // force High-res timer on - needs to be turned off at some point
// TDHEAEN | // enhanced accuracy?! This seems to add jitter
TDHREGEN | // sync to input clock - Closed loop running mode
TDHEN; // enable high speed clock
//set up timer for 132kHz
//TIMERD0:
TD0CTL1 = TDIDEX_0 | // _0: /1 _1: /2 _2: /3 ... _7: /8
TDCLKM_2 ; // _0: Ext Clk _1: Hires Clk _2: previous TDx Clk ### NULL for TD0 ###
TD0CTL0 = TDCLGRP_0 | // channels individual
CNTL_0 | // _0: 16Bit, _1: 12bit _2: 10bit _3: 8bit
TDSSEL_2 | // _0: TDCLK, _1: ACLK _2: SMCLK _3: inv TDCLK
ID_0 | // _0: /1 _1: /2 _2: /4 _3: /8
MC_3 | // _0: stop _1: up to TDCL0 _2: up overflow _3: up/down
TDCLR ; // Now that the clock to the timer is stopped, reset any timer start.
TD0CTL2 = 0; // channel capture mode register
TD0CCTL0 = 0; // channel 0 capture/compare settings
TD0CCTL1 = OUTMOD_2 | // PWM 0 - centred around count of zero
CLLD_1;
TD0CCTL2 = OUTMOD_6 | // PWM 180 - centred around max count
CLLD_1;
TD0CL0 = 486; // 128Mhz / 486 / 2 = 132kHz
TD0CL1 = 10; // minimum PWM_0 duty cycle
TD0CL2 = 486-10; // minimum PWM_180 duty cycle
while(!(TD0HINT | TDHLKIFG)); // wait for the PLL to lock
//Start!
TD0CTL1 = TDCLKM_1; // connect the timer to the hi res FLL
//get outputs setup to be active high, inactive low.
P1OUT &= ~BIT7;
P2OUT &= ~BIT0;
P1DIR |= BIT7;
P2DIR |= BIT0;
//set up GPIO ports for peripheral
P1SEL |= BIT7;
P2SEL |= BIT0;
}
void pwm_set_duty(unsigned int duty)
{
if( duty > PWM_Duty_Max) // ensures minimum duty cycle maintained
duty = PWM_Duty_Max;
if( duty < PWM_Duty_Min) // ensures successful update when using fast clock
duty = PWM_Duty_Min;
TD0CCR1 = duty;
duty = 486 - duty;
TD0CCR2 = duty;
}