Need help setting up PWM on FTM2_CH0 for output to PortB, bit 18.

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Need help setting up PWM on FTM2_CH0 for output to PortB, bit 18.

Jump to solution
1,219 Views
davepfaltzgraff
Senior Contributor I

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.

Labels (1)
1 Solution
806 Views
Jorge_Gonzalez
NXP Employee
NXP Employee

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

View solution in original post

0 Kudos
4 Replies
806 Views
davepfaltzgraff
Senior Contributor I

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.

0 Kudos
806 Views
Jorge_Gonzalez
NXP Employee
NXP Employee

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

0 Kudos
807 Views
Jorge_Gonzalez
NXP Employee
NXP Employee

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

0 Kudos
806 Views
davepfaltzgraff
Senior Contributor I

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