Hello,
I have modified the TPM_PWM example to use freeRTOS and drive a motor.
The PWM signal was very noisy when I checked with an oscilloscope and also with a motor controller as shown below.
I changed the PWM frequency and for some reasons, it seemed to work better with higher frequency then stopped working after some value.
When I was checking with the oscilloscope, the measuring frequency was also changing. I assume there might be something wrong with the TPM source clock?
Here is the code I used and the TPM1_CH0 pin was used to send PWM out.
What the code does is, once the SW3 button is pressed and Motor_Switch is true, the sinusoidal duty cycle of PWM is sent out.
/* Interrupt to enable and flag to read; depends on the TPM channel used */
#define TPM_CHANNEL_INTERRUPT_ENABLE kTPM_Chnl1InterruptEnable
#define TPM_CHANNEL_FLAG kTPM_Chnl1Flag
/* Get source clock for TPM driver */
#define TPM_SOURCE_CLOCK CLOCK_GetFreq(kCLOCK_PllFllSelClk)
void vMotor_Control_Task(void)
{
volatile uint16_t updatedDutycycle=0;
TickType_t xLastWakeTime;
tpm_config_t tpmInfo;
tpm_chnl_pwm_signal_param_t tpmParam;
#ifndef TPM_LED_ON_LEVEL
#define TPM_LED_ON_LEVEL kTPM_HighTrue
#endif
tpmParam.chnlNumber = (tpm_chnl_t)TPM_CHANNEL;
tpmParam.level = TPM_LED_ON_LEVEL;
tpmParam.dutyCyclePercent = 100U;
/* TPM known issue of KL81, enable clock of TPM0 to use other TPM module */
CLOCK_EnableClock(kCLOCK_Tpm1);
/* Select the clock source for the TPM counter as kCLOCK_PllFllSelClk */
CLOCK_SetTpmClock(1U);
TPM_GetDefaultConfig(&tpmInfo);
/* Initialize TPM module */
TPM_Init(TPM_BASEADDR, &tpmInfo);
TPM_SetupPwm(TPM_BASEADDR, &tpmParam, 1U, kTPM_EdgeAlignedPwm, 5000U, TPM_SOURCE_CLOCK);
TPM_StartTimer(TPM_BASEADDR, kTPM_SystemClock);
TPM_EnableInterrupts(TPM_BASEADDR,TPM_CHANNEL_INTERRUPT_ENABLE);
/* Disable channel output before updating the dutycycle */
TPM_UpdateChnlEdgeLevelSelect(TPM_BASEADDR, (tpm_chnl_t)TPM_CHANNEL, 0U);
int Motor_Switch = -1;
uint16_t Sin_time = 0;
while (1)
{
xLastWakeTime = xTaskGetTickCount();
if (g_ButtonPress)
{
PRINTF(" %s is pressed \r\n", BOARD_SW_NAME);
GPIO_PortToggle(BOARD_LED_GPIO, 1U << BOARD_LED_GPIO_PIN);
GPIO_PortToggle(EDO_GPIO, 1U << EDO_PIN);
Motor_Switch *= -1;
g_ButtonPress = false;
if(Motor_Switch==1)
{
PRINTF("Duty Cycle is on \r\n");
}
else
{
PRINTF("Duty Cycle is off \r\n");
Sin_time = 0;
updatedDutycycle = 100;
}
}
if (Motor_Switch==1)
{
updatedDutycycle = (uint16_t) 450 + 350*sin(2*PI*Sin_time/1000-PI/2);
/* Disable channel output before updating the dutycycle */
TPM_UpdateChnlEdgeLevelSelect(TPM_BASEADDR, (tpm_chnl_t)TPM_CHANNEL, 0U);
/* Update PWM duty cycle */
TPM_UpdatePwmDutycycle(TPM_BASEADDR, (tpm_chnl_t)TPM_CHANNEL, kTPM_EdgeAlignedPwm, updatedDutycycle);
/* Start channel output with updated dutycycle */
TPM_UpdateChnlEdgeLevelSelect(TPM_BASEADDR, (tpm_chnl_t)TPM_CHANNEL, TPM_LED_ON_LEVEL);
Sin_time++;
}
else
{
TPM_UpdateChnlEdgeLevelSelect(TPM_BASEADDR, (tpm_chnl_t)TPM_CHANNEL, 0U);
TPM_UpdatePwmDutycycle(TPM_BASEADDR, (tpm_chnl_t)TPM_CHANNEL, kTPM_EdgeAlignedPwm, 100U);
TPM_UpdateChnlEdgeLevelSelect(TPM_BASEADDR, (tpm_chnl_t)TPM_CHANNEL, TPM_LED_ON_LEVEL);
}
vTaskDelayUntil(&xLastWakeTime, 1);
}
}
Thank you.
Solved! Go to Solution.
Hi Yaeyong,
If you want PWM change continuously, you can't call TPM_UpdateChnlEdgeLevelSelect() before and after TPM_UpdatePwmDutycycle().
If you call TPM_UpdateChnlEdgeLevelSelect() and then TPM_UpdatePwmDutycycle, register TPM.C0V will update immediately. Current PWM waveform will be incomplete.
Another problem in your code is
updatedDutycycle = (uint16_t) 450 + 350*sin(2*PI*Sin_time/1000-PI/2);
updatedDutycycle is a uint8_t type. But your expression show that updatedDutycycle's value is from 100~800.
Regards,
Jing
Hi Yaeyong,
If you want PWM change continuously, you can't call TPM_UpdateChnlEdgeLevelSelect() before and after TPM_UpdatePwmDutycycle().
If you call TPM_UpdateChnlEdgeLevelSelect() and then TPM_UpdatePwmDutycycle, register TPM.C0V will update immediately. Current PWM waveform will be incomplete.
Another problem in your code is
updatedDutycycle = (uint16_t) 450 + 350*sin(2*PI*Sin_time/1000-PI/2);
updatedDutycycle is a uint8_t type. But your expression show that updatedDutycycle's value is from 100~800.
Regards,
Jing
Hello Jing,
Removing TPM_UpdateChnlEdgeLevelSelect() worked.
And I actually set updatedDutycycle to uint16_t before the attached code. Thanks for pointing it out though.
Thanks!.
Regards,
Jay