Hi, I'd like to generate a pwm with output compare mode on TPM in the FRDMK27 board.
I want to do this, without using the pwm function mode. It works fine.
I want to do this by output compare mode.
In this condition seem to be impossible to update the CnSC register to move the output pin high or low.
Only simply, I want to change the output with different timing
I show my simple code.
Can someone check this ?
Thanks.
Attilio
// init timer
void InitTimers(void)
{
SIM->SCGC6 |= SIM_SCGC6_TPM0_MASK; // clock gating
SIM->SOPT2 |= SIM_SOPT2_TPMSRC(0x10); // tpm clock source
TPM0->SC = TPM_SC_PS(0x07) | TPM_SC_CMOD(0x01); // prescaler divide 0x07 = 128 times
// tpm increment every tpm counter clock
TPM0->MOD = (UINT32)65535; // timer period value
TPM0->CONTROLS[TPM_CHANNEL_2].CnSC = 0x00 +\
TPM_CnSC_CHIE_MASK +\
TPM_CnSC_MSA_MASK +\
TPM_CnSC_ELSB_MASK +\
TPM_CnSC_ELSA_MASK; // out comp. set
TPM0->CONTROLS[TPM_CHANNEL_2].CnV = 5000; // first match after ~27ms
PORTA->PCR[5] = PORT_PCR_MUX(ALTERNATE_FUNCTION_3); // PTA5 wired to lamp
ConnectInterruptToCortex(TPM0_IRQn); // set TPM0 interrupt
}
// int.handler
void TPM0_IRQHandler(void)
{
static UINT8 counter, break_test;
UINT16 cnV;
UINT32 cnsC, status;
TPM_Type *tim = TPM0;
status = tim->STATUS;
// OVERFLOW
if(status & TPM_OVERFLOW_COUNTER)
{
break_test = 1;
}
// CH2
if(status & TPM_CH2_FLAG)
{
tim->CONTROLS[TPM_CHANNEL_2].CnSC |= 0x80; // flag reset
cnsC = tim->CONTROLS[TPM_CHANNEL_2].CnSC;
cnV = tim->CONTROLS[TPM_CHANNEL_2].CnV;
if(counter++ & 0x01)
{ // next match clear
cnsC &= ~TPM_CnSC_ELSA_MASK; // change
cnV = (cnV + 2000);
}
else
{ // next match set
cnsC |= TPM_CnSC_ELSA_MASK; // change
cnV = (cnV + 15000);
}
tim->CONTROLS[TPM_CHANNEL_2].CnV = cnV; // update regs
tim->CONTROLS[TPM_CHANNEL_2].CnSC = cnsC;
}
tim->STATUS |= status; // flag reset
}
Hi Attilio,
Please refer the TPM_UpdateChnlEdgeLevelSelect in fsl_tpm.c.
Best Regards,
Robin
-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------
Hi Robin, I thank you for following me. I couldn't answer you before.
I'd like to give what I like to get from TPM counter.
Try If, you can, to analyze my firmware.
I'd like to obtain an high controlled pulse every xxx ms. As in the example I sent,
the TPM output must be rimain low for 5ms * times. Or 15 ms.
Then I'd like to have a pulse high where the duration is 2 ms. The TPM clock is set for 1,5 Mhz and the code of
TPM_SetupOutputCompare is a mere copy of function I found in your previous suggestion.
Is it correct the code construction to obtain this goal ?
It doesn't work as I would like.Infact if I break when the switch case is 0 I'm expecting that the TPM out is 1.
And this happens. Then when the first instruction to disable the channel in TPM_SetupOutputCompare is executed the output goes low. And I think it's correct again. Then I wait till mode change to disable channel is acknowledged and after I set the new compare mode.
In this case the new compare mode is CLEAR on compare mode again. But as soon as the instruction is executed the output goes high.
And I think it's not correct this.
When the code run it does not work properly as I'm expecting. I think I do something wrong.
Thanks
Attilio
void TPM_SetupOutputCompare(TPM_Type *base, UINT8 chnlNumber, tpm_output_compare_mode_t compareMode, uint32_t compareValue)
{
base->CONTROLS[chnlNumber].CnSC &= ~(TPM_CnSC_MSA_MASK |
TPM_CnSC_MSB_MASK |
TPM_CnSC_ELSA_MASK |
TPM_CnSC_ELSB_MASK);
/* Wait till mode change to disable channel is acknowledged */
while (0U != (base->CONTROLS[chnlNumber].CnSC & (TPM_CnSC_MSA_MASK |
TPM_CnSC_MSB_MASK |
TPM_CnSC_ELSA_MASK |
TPM_CnSC_ELSB_MASK)))
{
}
base->CONTROLS[chnlNumber].CnSC |= (uint32_t)compareMode;
base->CONTROLS[chnlNumber].CnV = (base->CONTROLS[chnlNumber].CnV + compareValue) % base->MOD ; // *** have a look here
/* Wait till mode change is acknowledged */
while (0U == (base->CONTROLS[chnlNumber].CnSC & (TPM_CnSC_MSA_MASK |
TPM_CnSC_MSB_MASK |
TPM_CnSC_ELSA_MASK |
TPM_CnSC_ELSB_MASK)))
{
}
}
void TPM0_IRQHandler(void)
{
static UINT8 ph;
UINT32 status;
status = TPM0->STATUS;
if(status & TPM_CH2_FLAG)
{
switch(ph++)
{
case 0: TPM_SetupOutputCompare(TPM0, TPM_CHANNEL_2, kTPM_ClearOnMatch, 7500); break; // 5ms
case 1: TPM_SetupOutputCompare(TPM0, TPM_CHANNEL_2, kTPM_ClearOnMatch, 7500); break; // 5ms
case 2: TPM_SetupOutputCompare(TPM0, TPM_CHANNEL_2, kTPM_ClearOnMatch, 7500); break; // 5ms
case 3:
TPM_SetupOutputCompare(TPM0, TPM_CHANNEL_2, kTPM_SetOnMatch, 3000); // 2ms
ph = 0;
break;
}
}
TPM0->STATUS = status;
}
void InitTimers(void)
{
/* TIMER 0 channels setting */
SIM->SCGC6 |= SIM_SCGC6_TPM0_MASK; // clock gating
SIM->SOPT2 |= SIM_SOPT2_TPMSRC(0x10); // tpm clock source
TPM0->SC = TPM_SC_PS(0x04) | TPM_SC_CMOD(0x01); // prescaler divide 0x04 = 16 times
// tpm increment every tpm counter clock
TPM0->MOD = 60000; // timer period at 1,5 mhz of tpm clock = 40 ms
TPM0->CONTROLS[TPM_CHANNEL_2].CnSC = kTPM_ClearOnMatch +/
TPM_CnSC_CHIE_MASK;
TPM0->CONTROLS[TPM_CHANNEL_2].CnV = 7500; // first event after 5 ms
PORTA->PCR[5] = PORT_PCR_MUX(ALTERNATE_FUNCTION_3); // PTA5 wired to lamp
ConnectInterruptToCortex(TPM0_IRQn); // set TPM0 interrupt
}