KL03 PWM bare copper code not working

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

KL03 PWM bare copper code not working

Jump to solution
737 Views
stevengarfinkel
Contributor III

I am adding a pwm function to my code and it compiles but no PWM comes out of the pin.  I previously used the pin for GPIO so I know the hardware is functional.

Here is the code for initialization, which in this version leaves the outputs on at 50% dutycycle:

void PWM_init ()

{

  //Select time clock source

  //Select 48 MHz clock

  SIM->SOPT2 |= SIM_SOPT2_TPMSRC(1);

  //Enable the Clock to the timer Modules

  SIM_SCGC6 |= SIM_SCGC6_TPM0_MASK;

  SIM_SCGC6 |= SIM_SCGC6_TPM1_MASK;

  //Set pins to timer outputs

//PHA_LO = 7, PHB_LO = 10, PHC_LO = 11

  PORTB->PCR[B_PHALO] = PORT_PCR_MUX(2);

  PORTB->PCR[B_PHBLO] = PORT_PCR_MUX(2);

  PORTB->PCR[B_PHCLO] = PORT_PCR_MUX(2);

  //Enable clock, divide by 1

  TPM0_SC = 4;

  TPM1_SC = 4;

  //pwm frequency to 48MHz/20kHz = 2400;

  TPM0_MOD = 2400;

  TPM0_C0SC = 20; //Edge PWM

  TPM0_C0V = 1200;

  //PHC_LO

  TPM0_C1SC = 20;

  TPM0_C1V = 1200;

  //PHB_LO

  TPM1_MOD = 2400;

  TPM1_C0SC = 20;

  TPM1_C0V = 1200;

  //PHA_LO

}

I would greatly appreciate it if someone would point me to what I am not doing correctly.

Thanks so much!

Labels (1)
Tags (2)
0 Kudos
1 Solution
499 Views
mjbcswitzerland
Specialist V

Hi

1 Make sure that you have enabled the IRC48M by setting the HIRCEN bit in MCG_MC.

2. TPMx_MOD should be (2400 - 1) to give the exact frequency you want.

3. PTMx_CnSC of 0x28 is a known good value for PWM - yours (0x14) may be Ok but I didn't check.

4. TMPx_SC is best written as final command rather than before setting up the details (since it enables the operation)

5. I suspect the major issue is the TPMx_SC value since 4 divides the clock by 16 but doesn't enable the operation. Probably you wanted to set 8 in order to have a divide by 1 and start it.

I would always work with defines for the control bits to avoid such potential errors.

Below is the uTasker code to do this on the KL03, plus the simulated KL03 registers so that you can check your register values for comparison:

PWM_INTERRUPT_SETUP pwm_setup;

pwm_setup.int_type = PWM_INTERRUPT;

pwm_setup.pwm_mode = (PWM_IRC48M_CLK | PWM_PRESCALER_1);             // clock PWM timer from the IRC48M clock with /1 pre-scaler

pwm_setup.int_handler = 0;                                           // no user interrupt call-back or DMA on PWM cycle

pwm_setup.pwm_frequency = PWM_FREQUENCY(20000, 1);                   // generate 20kHz on PWM output

pwm_setup.pwm_value   = _PWM_PERCENT(50, pwm_setup.pwm_frequency);   // 50% PWM (high/low)

pwm_setup.pwm_reference = (_TIMER_0 | 0);                            // timer module 0, channel 0

fnConfigureInterrupt((void *)&pwm_setup);                            // enter configuration

pwm_setup.pwm_reference = (_TIMER_0 | 1);                            // timer module 0, channel 1

fnConfigureInterrupt((void *)&pwm_setup);                            // enter configuration

pwm_setup.pwm_reference = (_TIMER_1 | 0);                            // timer module 1, channel 0

fnConfigureInterrupt((void *)&pwm_setup);                            // enter configuration

TPM0:

pastedImage_0.png

TPM1:

pastedImage_1.png

Regards

Mark

P.S. As reference, I have attached the uTasker PWM interface code which is compatible for TPM or FlexTimer PWM operation on all chips, including interrupt and DMA operations.

View solution in original post

0 Kudos
2 Replies
500 Views
mjbcswitzerland
Specialist V

Hi

1 Make sure that you have enabled the IRC48M by setting the HIRCEN bit in MCG_MC.

2. TPMx_MOD should be (2400 - 1) to give the exact frequency you want.

3. PTMx_CnSC of 0x28 is a known good value for PWM - yours (0x14) may be Ok but I didn't check.

4. TMPx_SC is best written as final command rather than before setting up the details (since it enables the operation)

5. I suspect the major issue is the TPMx_SC value since 4 divides the clock by 16 but doesn't enable the operation. Probably you wanted to set 8 in order to have a divide by 1 and start it.

I would always work with defines for the control bits to avoid such potential errors.

Below is the uTasker code to do this on the KL03, plus the simulated KL03 registers so that you can check your register values for comparison:

PWM_INTERRUPT_SETUP pwm_setup;

pwm_setup.int_type = PWM_INTERRUPT;

pwm_setup.pwm_mode = (PWM_IRC48M_CLK | PWM_PRESCALER_1);             // clock PWM timer from the IRC48M clock with /1 pre-scaler

pwm_setup.int_handler = 0;                                           // no user interrupt call-back or DMA on PWM cycle

pwm_setup.pwm_frequency = PWM_FREQUENCY(20000, 1);                   // generate 20kHz on PWM output

pwm_setup.pwm_value   = _PWM_PERCENT(50, pwm_setup.pwm_frequency);   // 50% PWM (high/low)

pwm_setup.pwm_reference = (_TIMER_0 | 0);                            // timer module 0, channel 0

fnConfigureInterrupt((void *)&pwm_setup);                            // enter configuration

pwm_setup.pwm_reference = (_TIMER_0 | 1);                            // timer module 0, channel 1

fnConfigureInterrupt((void *)&pwm_setup);                            // enter configuration

pwm_setup.pwm_reference = (_TIMER_1 | 0);                            // timer module 1, channel 0

fnConfigureInterrupt((void *)&pwm_setup);                            // enter configuration

TPM0:

pastedImage_0.png

TPM1:

pastedImage_1.png

Regards

Mark

P.S. As reference, I have attached the uTasker PWM interface code which is compatible for TPM or FlexTimer PWM operation on all chips, including interrupt and DMA operations.

0 Kudos
499 Views
stevengarfinkel
Contributor III

Thanks again.  With your help I was able to figure it out and get it to work.

0 Kudos