TPM PWM Noise

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

TPM PWM Noise

Jump to solution
970 Views
songja
Contributor III

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.

PWM_reading.png

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.

Labels (1)
Tags (4)
0 Kudos
1 Solution
866 Views
jingpan
NXP TechSupport
NXP TechSupport

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

View solution in original post

0 Kudos
2 Replies
867 Views
jingpan
NXP TechSupport
NXP TechSupport

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

0 Kudos
866 Views
songja
Contributor III

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

0 Kudos