I am adding a pwm function to my code and it compiles but no PWM comes out of the pin. I previously used the pin for GPIO so I know the hardware is functional.
Here is the code for initialization, which in this version leaves the outputs on at 50% dutycycle:
void PWM_init ()
{
//Select time clock source
//Select 48 MHz clock
SIM->SOPT2 |= SIM_SOPT2_TPMSRC(1);
//Enable the Clock to the timer Modules
SIM_SCGC6 |= SIM_SCGC6_TPM0_MASK;
SIM_SCGC6 |= SIM_SCGC6_TPM1_MASK;
//Set pins to timer outputs
//PHA_LO = 7, PHB_LO = 10, PHC_LO = 11
PORTB->PCR[B_PHALO] = PORT_PCR_MUX(2);
PORTB->PCR[B_PHBLO] = PORT_PCR_MUX(2);
PORTB->PCR[B_PHCLO] = PORT_PCR_MUX(2);
//Enable clock, divide by 1
TPM0_SC = 4;
TPM1_SC = 4;
//pwm frequency to 48MHz/20kHz = 2400;
TPM0_MOD = 2400;
TPM0_C0SC = 20; //Edge PWM
TPM0_C0V = 1200;
//PHC_LO
TPM0_C1SC = 20;
TPM0_C1V = 1200;
//PHB_LO
TPM1_MOD = 2400;
TPM1_C0SC = 20;
TPM1_C0V = 1200;
//PHA_LO
}
I would greatly appreciate it if someone would point me to what I am not doing correctly.
Thanks so much!
Solved! Go to Solution.
Hi
1 Make sure that you have enabled the IRC48M by setting the HIRCEN bit in MCG_MC.
2. TPMx_MOD should be (2400 - 1) to give the exact frequency you want.
3. PTMx_CnSC of 0x28 is a known good value for PWM - yours (0x14) may be Ok but I didn't check.
4. TMPx_SC is best written as final command rather than before setting up the details (since it enables the operation)
5. I suspect the major issue is the TPMx_SC value since 4 divides the clock by 16 but doesn't enable the operation. Probably you wanted to set 8 in order to have a divide by 1 and start it.
I would always work with defines for the control bits to avoid such potential errors.
Below is the uTasker code to do this on the KL03, plus the simulated KL03 registers so that you can check your register values for comparison:
PWM_INTERRUPT_SETUP pwm_setup;
pwm_setup.int_type = PWM_INTERRUPT;
pwm_setup.pwm_mode = (PWM_IRC48M_CLK | PWM_PRESCALER_1); // clock PWM timer from the IRC48M clock with /1 pre-scaler
pwm_setup.int_handler = 0; // no user interrupt call-back or DMA on PWM cycle
pwm_setup.pwm_frequency = PWM_FREQUENCY(20000, 1); // generate 20kHz on PWM output
pwm_setup.pwm_value = _PWM_PERCENT(50, pwm_setup.pwm_frequency); // 50% PWM (high/low)
pwm_setup.pwm_reference = (_TIMER_0 | 0); // timer module 0, channel 0
fnConfigureInterrupt((void *)&pwm_setup); // enter configuration
pwm_setup.pwm_reference = (_TIMER_0 | 1); // timer module 0, channel 1
fnConfigureInterrupt((void *)&pwm_setup); // enter configuration
pwm_setup.pwm_reference = (_TIMER_1 | 0); // timer module 1, channel 0
fnConfigureInterrupt((void *)&pwm_setup); // enter configuration
TPM0:
TPM1:
Regards
Mark
P.S. As reference, I have attached the uTasker PWM interface code which is compatible for TPM or FlexTimer PWM operation on all chips, including interrupt and DMA operations.
Hi
1 Make sure that you have enabled the IRC48M by setting the HIRCEN bit in MCG_MC.
2. TPMx_MOD should be (2400 - 1) to give the exact frequency you want.
3. PTMx_CnSC of 0x28 is a known good value for PWM - yours (0x14) may be Ok but I didn't check.
4. TMPx_SC is best written as final command rather than before setting up the details (since it enables the operation)
5. I suspect the major issue is the TPMx_SC value since 4 divides the clock by 16 but doesn't enable the operation. Probably you wanted to set 8 in order to have a divide by 1 and start it.
I would always work with defines for the control bits to avoid such potential errors.
Below is the uTasker code to do this on the KL03, plus the simulated KL03 registers so that you can check your register values for comparison:
PWM_INTERRUPT_SETUP pwm_setup;
pwm_setup.int_type = PWM_INTERRUPT;
pwm_setup.pwm_mode = (PWM_IRC48M_CLK | PWM_PRESCALER_1); // clock PWM timer from the IRC48M clock with /1 pre-scaler
pwm_setup.int_handler = 0; // no user interrupt call-back or DMA on PWM cycle
pwm_setup.pwm_frequency = PWM_FREQUENCY(20000, 1); // generate 20kHz on PWM output
pwm_setup.pwm_value = _PWM_PERCENT(50, pwm_setup.pwm_frequency); // 50% PWM (high/low)
pwm_setup.pwm_reference = (_TIMER_0 | 0); // timer module 0, channel 0
fnConfigureInterrupt((void *)&pwm_setup); // enter configuration
pwm_setup.pwm_reference = (_TIMER_0 | 1); // timer module 0, channel 1
fnConfigureInterrupt((void *)&pwm_setup); // enter configuration
pwm_setup.pwm_reference = (_TIMER_1 | 0); // timer module 1, channel 0
fnConfigureInterrupt((void *)&pwm_setup); // enter configuration
TPM0:
TPM1:
Regards
Mark
P.S. As reference, I have attached the uTasker PWM interface code which is compatible for TPM or FlexTimer PWM operation on all chips, including interrupt and DMA operations.
Thanks again. With your help I was able to figure it out and get it to work.