I am trying to set up a FRDM-K22F board so that Port b, bit 18 is a PWM signal out. (This is connected to the header J1, pin 12.)
My code is as follows:
=====
ftm_pwm_param_t PWM_Param = {
kFtmEdgeAlignedPWM,
kFtmHighTrue,
20000, // Frequency
50, // Duty cycle (0 - 100!!)
0
};
....
// Set up the PWM hardware for FTM2_CH0 on Port B, bit 18
PORT_HAL_SetMuxMode(PORTB, 18u, kPortMuxAlt3);
GPIO_HAL_SetPinDir(PTB, 18u, kGpioDigitalOutput);
PORT_HAL_SetDriveStrengthMode(PORTB, 18u, kPortLowDriveStrength);
PORT_HAL_SetSlewRateMode(PORTB, 18u, kPortSlowSlewRate);
SIM_HAL_EnableClock(SIM, kSimClockGateFtm2);
FTM_HAL_Init(FTM2);
FTM_HAL_SetClockSource(FTM2, kClock_source_FTM_None);
FTM_HAL_SetClockPs(FTM2, kFtmDividedBy2);
FTM_HAL_SetMod(FTM2, 0xFFFE);
FTM_HAL_EnablePwmMode(FTM2, &PWM_Param, CHAN0_IDX);
FTM_HAL_SetBdmMode(FTM2, kFtmBdmMode_11);
=====
What am I missing that prevents the PWM signal from appearing on the pin?
I Know that Port B, pin 18 is the right one as I was able to replace the kPortMuxAlt3 in the first line with a kPortMusAsGpio and before the SIM_HAL line insert an infinite loop toggling the bit and it shows up on the scope.
To answer the anticipated question of why I wouldn't use the FTM_DRV series of routines: These routines limit the output resolution to a range of 0 to 100. For my application I need much higher resolution and plan to use the full 16-bit capability.
Thanks for any pointers.
Solved! Go to Solution.
Hello David,
Try with the next code. You can compare and see how it is almost the same as the driver, with the difference of calculating modulo and channel value with a duty cycle resolution of 0-1000, setting the duty to 475/1000.
int main(void)
{
uint32_t uFTMhz;
uint16_t uMod, uCnv;
uint8_t clkPs;
ftm_pwm_param_t PWM_Param =
{
kFtmEdgeAlignedPWM,
kFtmHighTrue,
20000, // Frequency
475, // Duty cycle (0 - 1000!!)
0
};
CLOCK_SYS_EnablePortClock(PORTB_IDX);
PORT_HAL_SetMuxMode(PORTB,18u,kPortMuxAlt3);
SIM_HAL_EnableClock(SIM, kSimClockGateFtm2);
FTM_HAL_Init(FTM2);
FTM_HAL_SetClockPs(FTM2, kFtmDividedBy1);
FTM_HAL_EnablePwmMode(FTM2, &PWM_Param, CHAN0_IDX);
clkPs = (1 << FTM_HAL_GetClockPs(FTM2));
uFTMhz = CLOCK_SYS_GetFtmSystemClockFreq(FTM2_IDX) / clkPs;
FTM_HAL_SetCounterInitVal(FTM2, 0);
uMod = uFTMhz / (PWM_Param.uFrequencyHZ) - 1;
uCnv = uMod * PWM_Param.uDutyCyclePercent / 1000;
FTM_HAL_SetMod(FTM2, uMod);
FTM_HAL_SetChnCountVal(FTM2, CHAN0_IDX, uCnv);
FTM_HAL_SetClockSource(FTM2, kClock_source_FTM_SystemClk);
for (;;){ }
/* Never leave main */
return 0;
}
Regards!
Jorge Gonzalez
I changed the line from:
FTM_HAL_SetClockSource(FTM2, kClock_source_FTM_None);
to:
FTM_HAL_SetClockSource(FTM2, kClock_source_FTM_SystemClk);
and now at least the output goes high when I execute the code.
Some progress, but still no PWM.
Hello David:
By checking your code the first thing I notice is that you are not setting the Channel count value using FTM_HAL_SetChnCountVal(). The channel value should be set for the output to be cleared on match in this case.
Also, please notice that if not using the FTM driver, then the frequency and duty cycle you define in your PWM_Param structure will not be used directly, so you need to use the HAL to adjust the prescaler, modulo and channel value to obtain the required frequency and duty.
If you require a higher resolution than 0-100 maybe you can instead adapt the driver and rebuild the KSDK platform library. It is just the function FTM_DRV_PwmStart()
Regards!
Jorge Gonzalez
Hello David,
Try with the next code. You can compare and see how it is almost the same as the driver, with the difference of calculating modulo and channel value with a duty cycle resolution of 0-1000, setting the duty to 475/1000.
int main(void)
{
uint32_t uFTMhz;
uint16_t uMod, uCnv;
uint8_t clkPs;
ftm_pwm_param_t PWM_Param =
{
kFtmEdgeAlignedPWM,
kFtmHighTrue,
20000, // Frequency
475, // Duty cycle (0 - 1000!!)
0
};
CLOCK_SYS_EnablePortClock(PORTB_IDX);
PORT_HAL_SetMuxMode(PORTB,18u,kPortMuxAlt3);
SIM_HAL_EnableClock(SIM, kSimClockGateFtm2);
FTM_HAL_Init(FTM2);
FTM_HAL_SetClockPs(FTM2, kFtmDividedBy1);
FTM_HAL_EnablePwmMode(FTM2, &PWM_Param, CHAN0_IDX);
clkPs = (1 << FTM_HAL_GetClockPs(FTM2));
uFTMhz = CLOCK_SYS_GetFtmSystemClockFreq(FTM2_IDX) / clkPs;
FTM_HAL_SetCounterInitVal(FTM2, 0);
uMod = uFTMhz / (PWM_Param.uFrequencyHZ) - 1;
uCnv = uMod * PWM_Param.uDutyCyclePercent / 1000;
FTM_HAL_SetMod(FTM2, uMod);
FTM_HAL_SetChnCountVal(FTM2, CHAN0_IDX, uCnv);
FTM_HAL_SetClockSource(FTM2, kClock_source_FTM_SystemClk);
for (;;){ }
/* Never leave main */
return 0;
}
Regards!
Jorge Gonzalez
Hi Jorge,
Thanks for the code example. I was missing both setting the initial value as well as the count value.
However, it seems as though there may be something that is order dependent as well. It didn't work for me until I put my code in the same order.
Now at least I have a PWM output and I can tweak the parameters from there.
Thanks