MKW30Z; SDK1.3; IAR 7.50; TPM PWM set duty cycle faster

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

MKW30Z; SDK1.3; IAR 7.50; TPM PWM set duty cycle faster

Jump to solution
918 Views
lucianfiran
Contributor V
KW40Z_Connectivity_Software_1.0.1 (KSDK_1.3.0)
I need to change a led PWM duty cycle over time. (for fade in/fade out)
Is there a faster way to change only the duty cycle to set the TPM channel ?
(usign only once TPM_DRV_PwmStart at initialization)

 

Something like:

 

TPM_DRV_SetEdgeAlignedPWMduty (uint32_t instance, uint8_t channel, uint8_t uDutyCyclePercent)

 

PwmStart seems to me a lot of code to do a simple change for duty cycle.
Labels (1)
Tags (3)
0 Kudos
1 Solution
633 Views
xiangjun_rong
NXP TechSupport
NXP TechSupport

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

View solution in original post

4 Replies
634 Views
xiangjun_rong
NXP TechSupport
NXP TechSupport

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

633 Views
lucianfiran
Contributor V

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); 
}

0 Kudos
633 Views
lucianfiran
Contributor V

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, &param0,  BOARD_TPM_CHANNEL_0_0);
    TPM_DRV_PwmStart(BOARD_TPM_INSTANCE_0, &param1,  BOARD_TPM_CHANNEL_0_1);
    TPM_DRV_PwmStart(BOARD_TPM_INSTANCE_0, &param2,  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.

0 Kudos
633 Views
lucianfiran
Contributor V

My short pwm function looks good:

pastedImage_1.png

pastedImage_3.png

pastedImage_4.png

but the function TPM_DRV_PwmStart pwm generate glitches if changing the same duty cycle near 0%

pastedImage_8.png

So another possible workaround is to see if newDutyCycle != oldDutyCicle - only then use the function.

0 Kudos