Something like:
TPM_DRV_SetEdgeAlignedPWMduty (uint32_t instance, uint8_t channel, uint8_t uDutyCyclePercent)
Solved! Go to Solution.
Hi,
From hardware perspective, it is okay to write the TPMx_CnV and TPMx_MOD registers directly if you want to change the duty cycle or PWM cycle time, you do not need any other operation. In order to keep the PWM cycle intact, the TPMx_CnV and TPMx_MOD registers have internal buffer, the registers will update when the TPM counter changes from MOD to zero in EPWM mode or from MOD to (MOD – 1) in CPWM mode.
Pls refer to section 32.4.13 Registers Updated from Write Buffers in RM of KW30.
In conclusion, it is okay to call TPM_DRV_SetEdgeAlignedPWMduty (uint32_t instance, uint8_t channel, uint8_t uDutyCyclePercent) when you want to update the PWM duty cycle.
BR
Xiangjun Rong
Hi,
From hardware perspective, it is okay to write the TPMx_CnV and TPMx_MOD registers directly if you want to change the duty cycle or PWM cycle time, you do not need any other operation. In order to keep the PWM cycle intact, the TPMx_CnV and TPMx_MOD registers have internal buffer, the registers will update when the TPM counter changes from MOD to zero in EPWM mode or from MOD to (MOD – 1) in CPWM mode.
Pls refer to section 32.4.13 Registers Updated from Write Buffers in RM of KW30.
In conclusion, it is okay to call TPM_DRV_SetEdgeAlignedPWMduty (uint32_t instance, uint8_t channel, uint8_t uDutyCyclePercent) when you want to update the PWM duty cycle.
BR
Xiangjun Rong
on HAL level it could look like:
uMod is calculated at init level ( and depends by TPM_DRV_SetClock params and BOARD_TPM_FRQ_HZ constant)
#define BOARD_TPM_INSTANCE_0 0
#define BOARD_TPM_CHANNEL_0_0 0
#define BOARD_TPM_CHANNEL_0_1 1
#define BOARD_TPM_CHANNEL_0_2 2
#define BOARD_TPM_MODE kTpmEdgeAlignedPWM
#define BOARD_TPM_FRQ_HZ 120000u
uint16_t uMod;
void BOARD_InitTPM(void)
{
uint32_t freq;
uint32_t val;
tpm_clock_mode_t clkSrc;
TPM_Type *tpmBase = g_tpmBase[BOARD_TPM_INSTANCE_0];
/* Initialize TPM module for PWM generation */
tpm_general_config_t driverInfo_0 = { //TPM 0 configuration structure
.isDBGMode = FALSE,
.isGlobalTimeBase = FALSE,
.isTriggerMode = FALSE,
.isStopCountOnOveflow = FALSE,
.isCountReloadOnTrig = FALSE,
.triggerSource = kTpmTrigSel0,
};
PORT_HAL_SetMuxMode(PORTB,18u,kPortMuxAlt5); /* TPM0_CH0 */
PORT_HAL_SetMuxMode(PORTC, 0u,kPortMuxAlt5); /* TPM0_CH1 */
PORT_HAL_SetMuxMode(PORTC, 1u,kPortMuxAlt5); /* TPM0_CH2 */
// Init TPM
TPM_DRV_Init(BOARD_TPM_INSTANCE_RGB, &driverInfo_0);
// Set clock for TPM COLOR
TPM_DRV_SetClock(BOARD_TPM_INSTANCE_RGB, kTpmClockSourceModuleClk, kTpmDividedBy2);
//instance init
clkSrc = TPM_HAL_GetClockMode(tpmBaseRGB);
/* Disable counter when switching modes */
TPM_HAL_SetClockMode(tpmBase, kTpmClockSourceNoneClk);
TPM_HAL_SetCpwms(tpmBaseRGB, BOARD_TPM_MODE);
/* Restore the clock source */
TPM_HAL_SetClockMode(tpmBase, clkSrc);
#if (BOARD_TPM_MODE == kTpmEdgeAlignedPWM )
val = ((uint32_t) 2 ) << TPM_CnSC_ELSA_SHIFT;
#else
val = ((uint32_t) 1 ) << TPM_CnSC_ELSA_SHIFT;
#endif
val |= (2 << TPM_CnSC_MSA_SHIFT);
TPM_HAL_SetChnMsnbaElsnbaVal(tpmBase, BOARD_TPM_CHANNEL_0_0, val);
TPM_HAL_SetChnMsnbaElsnbaVal(tpmBase, BOARD_TPM_CHANNEL_0_1, val);
TPM_HAL_SetChnMsnbaElsnbaVal(tpmBase, BOARD_TPM_CHANNEL_0_2, val);
/* Wait till mode change is acknowledged */
while (!(TPM_HAL_GetChnMsnbaVal(tpmBaseRGB, BOARD_TPM_CHANNEL_0_0))) { }
while (!(TPM_HAL_GetChnMsnbaVal(tpmBaseRGB, BOARD_TPM_CHANNEL_0_1))) { }
while (!(TPM_HAL_GetChnMsnbaVal(tpmBaseRGB, BOARD_TPM_CHANNEL_0_2))) { }
freq = TPM_DRV_GetClock(BOARD_TPM_INSTANCE_0);
#if (BOARD_TPM_MODE == kTpmEdgeAlignedPWM )
uMod = freq / BOARD_TPM_FRQ_HZ - 1;
TPM_HAL_SetMod(tpmBase, uMod);
#else
uMod = freq / (BOARD_TPM_FRQ_HZ * 2);
TPM_HAL_SetMod(tpmBase, uMod);
#endif
}
void BOARD_TPM_0_0(uint32_t dutyCycle)
{
uint16_t uCnv;
TPM_Type *tpmBase = g_tpmBase[BOARD_TPM_INSTANCE_0];
uCnv = uMod * dutyCycle / 100;
/* For 100% duty cycle */
if(uCnv >= uMod)
{
uCnv = uMod + 1;
}
TPM_HAL_SetChnCountVal(tpmBase, BOARD_TPM_CHANNEL_0_0, uCnv);
}
When I use the fsl_tmp_driver to fast update pwm for 3 led channels I got some unpleasant flickering.
I change only duty cycle.
The workaround found and working, is to init and start PWM in init_function:
TPM_DRV_Init(BOARD_TPM_INSTANCE_0, &driverInfo_0);
TPM_DRV_SetClock(BOARD_TPM_INSTANCE_0, kTpmClockSourceModuleClk, kTpmDividedBy2);
and start pwm once
TPM_DRV_PwmStart(BOARD_TPM_INSTANCE_0, ¶m0, BOARD_TPM_CHANNEL_0_0);
TPM_DRV_PwmStart(BOARD_TPM_INSTANCE_0, ¶m1, BOARD_TPM_CHANNEL_0_1);
TPM_DRV_PwmStart(BOARD_TPM_INSTANCE_0, ¶m2, BOARD_TPM_CHANNEL_0_2);
(get in debug mode get the magic number uMod inside TPM_DRV_PwmStart for my particular setting)
then update PWM like this:
void BOARD_TPM_out(uint8_t dutyCycle0, uint8_t dutyCycle1, uint8_t dutyCycle2)
{
uint16_t uCnv0, uCnv1, uCnv2;
uint16_t uMod = 132; // get from debug TPM_DRV_PwmStart function
TPM_Type *tpmBase = g_tpmBase[BOARD_TPM_INSTANCE_0];
uCnv0 = uMod * dutyCycle0 / 100;
/* For 100% duty cycle */
if(uCnv0 >= uMod) { uCnv0 = uMod + 1; }
uCnv1 = uMod * dutyCycle1 / 100;
/* For 100% duty cycle */
if(uCnv1 >= uMod) { uCnv1 = uMod + 1; }
uCnv2 = uMod * dutyCycle2 / 100;
/* For 100% duty cycle */
if(uCnv2 >= uMod) { uCnv2 = uMod + 1; }
TPM_HAL_SetChnCountVal(tpmBase, BOARD_TPM_CHANNEL_0_0, uCnv0);
TPM_HAL_SetChnCountVal(tpmBase, BOARD_TPM_CHANNEL_0_1, uCnv1);
TPM_HAL_SetChnCountVal(tpmBase, BOARD_TPM_CHANNEL_0_2, uCnv2);
}
I think some sort of fast PWM function should be implemented in fsl_tmp_driver.
Lucian.
My short pwm function looks good:
but the function TPM_DRV_PwmStart pwm generate glitches if changing the same duty cycle near 0%
So another possible workaround is to see if newDutyCycle != oldDutyCicle - only then use the function.