TPM K27 - CnSC register updating on output compare mode

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

TPM K27 - CnSC register updating on output compare mode

703 Views
attiliorossi321
Contributor II

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
}

Labels (1)
0 Kudos
2 Replies

613 Views
Robin_Shen
NXP TechSupport
NXP TechSupport

Hi Attilio,

Please refer the TPM_UpdateChnlEdgeLevelSelect in fsl_tpm.c.

TPM_UpdateChnlEdgeLevelSelect.png

Best Regards,

Robin

 

-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------

0 Kudos

613 Views
attiliorossi321
Contributor II

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
}

0 Kudos