K64 driver for standard PWM always resets start point

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

K64 driver for standard PWM always resets start point

Jump to solution
1,044 Views
CarlFST60L
Senior Contributor II

Hi,

 

I have a very very simple requirement but just couldn't seem to find the answer in a reasonable amount of time.

I am using MCUXpresso and the K64 baremetal C drivers supplied. This job is super simple, I just have two PWM's on FTM0.I just want 100Hz PWM with varied high time, super simple motor controller application. For some reason the gap between high pulses varies when i update the PWM using the driver like this instead of just changing the hi time it seems to "start agian" or something and the low time increases between pulses.

I read the reference manual and figered i should set it like this:

//SETUP

ftm_config_t ftmInfo;

ftm_chnl_pwm_signal_param_t ftmParam[2];

PORT_SetPinMux(RC1_M_PORT, RC1_M_PIN, RC1_M_ALT);
PORT_SetPinMux(RC2_M_PORT, RC2_M_PIN, RC2_M_ALT);

ftmParam[0].chnlNumber = (ftm_chnl_t)RC1CH_PWM;
ftmParam[0].level = kFTM_LowTrue;
ftmParam[0].dutyCyclePercent = 0U;
ftmParam[0].firstEdgeDelayPercent = 0U;
ftmParam[0].enableDeadtime = false;

ftmParam[1].chnlNumber = (ftm_chnl_t)RC2CH_PWM;
ftmParam[1].level = kFTM_LowTrue;
ftmParam[1].dutyCyclePercent = 0U;
ftmParam[1].firstEdgeDelayPercent = 0U;
ftmParam[1].enableDeadtime = false;

FTM_GetDefaultConfig(&ftmInfo);
ftmInfo.prescale = kFTM_Prescale_Divide_16;
ftmInfo.pwmSyncMode = (uint32_t)kFTM_SoftwareTrigger;

//I thought this flag hsould tell it to update the PWM when it clocks back over to min and i should get my perfect 2XKhz PWM with varied "high time"

ftmInfo.reloadPoints = kFTM_CntMin;
FTM_Init(FTM0, &ftmInfo);

if(FTM_SetupPwm(FTM0, ftmParam, 2U, kFTM_EdgeAlignedPwm, 100U, TPM_SOURCE_CLOCK) != kStatus_Success)
{
while(1);  //Stop for debug
}
FTM_StartTimer(FTM0, kFTM_SystemClock);

FTM_SetDutyCycle(FTM0, (ftm_chnl_t)RC1CH_PWM, 0);
FTM_SetDutyCycle(FTM0, (ftm_chnl_t)RC2CH_PWM, 0);

....

for(;;)

{

//software to do things to the PWM values

FTM_SetDutyCycle(FTM0, (ftm_chnl_t)RC1CH_PWM, new_HighTimePulseValue);

FTM_SetDutyCycle(FTM0, (ftm_chnl_t)RC2CH_PWM, new_LowTimePUlseValue);
FTM_SetSoftwareTrigger(FTM0, true);

}

//I dont want to use a percentage, i want exact numbers for my PWM, so I just made this function which does the same as the drvier FTM_UpdatePwmDutycycle(); function

void FTM_SetDutyCycle(FTM_Type *base, ftm_chnl_t chnlNumber, uint16_t dutyCycle)
{
 base->CONTROLS[chnlNumber].CnV = dutyCycle;
}

I just want exactly 100Hz PWM with my custom high time... 

0 Kudos
1 Solution
1,029 Views
CarlFST60L
Senior Contributor II

You guys need to update your example to either include this as an option, or, just turn it off

I have created this function call to fix the problem of PWM resetting its count.

I cannot really imagine many real examples where you would want your PWM to "start again" randomly or use this feature... 

uint16_t FTM_DisableReset(FTM_Type *base)
{
base->SYNCONF &= (~FTM_SYNCONF_SWRSTCNT_MASK);
return base->SYNCONF;
}

View solution in original post

0 Kudos
2 Replies
1,035 Views
CarlFST60L
Senior Contributor II

Ok, so I have produced the problem using the supplied example driver from MCUXpresso!

To produce the fault and see it on scope simply slow the PWM down to 100hz (and prescaler /16 as required) and you can continually see it break PWM timing

Here is the code and some images showing that it sometimes destroys the PWM and outputs the wrong timing completely

void delay(void)
{
volatile uint32_t i = 0U;
for (i = 0U; i < 10000000U; ++i)
{
__asm("NOP"); /* delay */
}
}

int main(void)
{
/* Init board hardware. */
uint32_t error = 0;
BOARD_InitBootPins();
Global_IOConfig();
BOARD_InitBootClocks();

//TEST START
{
uint8_t prevupdatedDutycycle = 0;
bool brightnessUp = true; /* Indicate LEDs are brighter or dimmer */
ftm_config_t ftmInfo;
uint8_t updatedDutycycle = 0U;
ftm_chnl_pwm_signal_param_t ftmParam[2];
/* Configure ftm params with frequency 24kHZ */
ftmParam[0].chnlNumber = (ftm_chnl_t)RC1CH_PWM;
ftmParam[0].level = kFTM_LowTrue;
ftmParam[0].dutyCyclePercent = 0U;
ftmParam[0].firstEdgeDelayPercent = 0U;
ftmParam[0].enableDeadtime = false;

ftmParam[1].chnlNumber = (ftm_chnl_t)RC2CH_PWM;
ftmParam[1].level = kFTM_LowTrue;
ftmParam[1].dutyCyclePercent = 0U;
ftmParam[1].firstEdgeDelayPercent = 0U;
ftmParam[1].enableDeadtime = false;

PORT_SetPinMux(RC1_M_PORT, RC1_M_PIN, RC1_M_ALT);
PORT_SetPinMux(RC2_M_PORT, RC2_M_PIN, RC2_M_ALT);

/* Print a note to terminal */
PRINTF("\r\nFTM example to output PWM on 2 channels\r\n");
PRINTF("\r\nYou will see a change in LED brightness if an LED is connected to the FTM pin");
PRINTF("\r\nIf no LED is connected to the FTM pin, then probe the signal using an oscilloscope");

/*
* ftmInfo.prescale = kFTM_Prescale_Divide_1;
* ftmInfo.bdmMode = kFTM_BdmMode_0;
* ftmInfo.pwmSyncMode = kFTM_SoftwareTrigger;
* ftmInfo.reloadPoints = 0;
* ftmInfo.faultMode = kFTM_Fault_Disable;
* ftmInfo.faultFilterValue = 0;
* ftmInfo.deadTimePrescale = kFTM_Deadtime_Prescale_1;
* ftmInfo.deadTimeValue = 0;
* ftmInfo.extTriggers = 0;
* ftmInfo.chnlInitState = 0;
* ftmInfo.chnlPolarity = 0;
* ftmInfo.useGlobalTimeBase = false;
*/
FTM_GetDefaultConfig(&ftmInfo);
/* Initialize FTM module */
ftmInfo.prescale = kFTM_Prescale_Divide_16;

FTM_Init(FTM0, &ftmInfo);
// FTM_SetupPwm(FTM0, ftmParam, 2U, kFTM_EdgeAlignedPwm, 24000U, CLOCK_GetFreq(kCLOCK_BusClk));
//My Version
FTM_SetupPwm(FTM0, ftmParam, 2U, kFTM_EdgeAlignedPwm, 100U, TPM_SOURCE_CLOCK);

FTM_StartTimer(FTM0, kFTM_SystemClock);
while (1)
{
/* Delay to see the change of LEDs brightness */
delay();

if (brightnessUp)
{
/* Increase duty cycle until it reach limited value */
if (++updatedDutycycle == 100U)
{
brightnessUp = false;
}
}
else
{
/* Decrease duty cycle until it reach limited value */
if (--updatedDutycycle == 0U)
{
brightnessUp = true;
}
}
// if(prevupdatedDutycycle != updatedDutycycle)
{
prevupdatedDutycycle = updatedDutycycle;
/* Start PWM mode with updated duty cycle */
FTM_UpdatePwmDutycycle(FTM0, (ftm_chnl_t)RC1CH_PWM, kFTM_EdgeAlignedPwm, updatedDutycycle);
FTM_UpdatePwmDutycycle(FTM0, (ftm_chnl_t)RC2CH_PWM, kFTM_EdgeAlignedPwm, updatedDutycycle);
/* Software trigger to update registers */
FTM_SetSoftwareTrigger(FTM0, true);
}
}
}

}

You can see the attached view with examples of this. It happens "a lot". This PWM configuration is dangerous and certainly not obvious this is how the driver works.

 

How do I make it keep timing, i need that 100Hz to ALWAYS be 100Hz

 

0 Kudos
1,030 Views
CarlFST60L
Senior Contributor II

You guys need to update your example to either include this as an option, or, just turn it off

I have created this function call to fix the problem of PWM resetting its count.

I cannot really imagine many real examples where you would want your PWM to "start again" randomly or use this feature... 

uint16_t FTM_DisableReset(FTM_Type *base)
{
base->SYNCONF &= (~FTM_SYNCONF_SWRSTCNT_MASK);
return base->SYNCONF;
}

0 Kudos