FRDM-KL03Z: Need help with interrupts in TPM module!

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

FRDM-KL03Z: Need help with interrupts in TPM module!

Jump to solution
1,979 Views
sarastout-grand
Contributor III

Hello,

I have the following code set-up to trigger an interrupt when the timer on channel 0 overflows. I have written an interrupt handler, but the various items in the routine are not being implemented. Also, when I try to reset the interrupt flags by writing a "1" to the appropriate registers, they appear to stay set and not get cleared. My code is below.

I'm also confused by the LED color since LED3 is supposed to be blue but I see green.

Thanks!

#include <stdio.h>
#include <string.h>

// SDK Included Files
#include "fsl_tpm_driver.h"
#include "board.h"
#include "fsl_debug_console.h"
#include "fsl_interrupt_manager.h"


//Code to use the TPM interrupt

int main(void)
{

    uint16_t uMod, uCnV;
    uint32_t freq, instance, clockps,port;
    uint8_t channel, value;

    hardware_init();
    instance=BOARD_TPM_INSTANCE;
    channel= BOARD_TPM_CHANNEL;

    CLOCK_SYS_EnableTpmClock(instance);

    TPM_Type *tpmbase=g_tpmBase[instance];

    //Set Port (Ports are already set in the pins_mux.c file)
   // PORT_WR_PCR_MUX(PORTB, 11, 010); //Set the Alt2 muxing on Port B, pin 11
   // GPIO_WR_PCOR(gpioBase, 0u);//Clear the output port
    //GPIO_WR_PDDR(portBase, 1u); //Set Port as output

    //Set up the Timer
    TPM_BWR_SC_PS(tpmbase, 1u); //Set the prescaler value to divide by 2
    TPM_BWR_SC_CMOD(tpmbase, 00); //Disable the counter until the MOD is set
    TPM_BWR_SC_CPWMS(tpmbase, 0u); //Set the counting mode to up only
    TPM_BWR_CNT_COUNT(tpmbase,35u); //Set the count value, writing any value clears the register

    clockps=(1<<TPM_BRD_SC_PS(tpmbase));
    freq=CLOCK_SYS_GetTpmFreq(instance)/clockps; //System clock=48MHz
    //uMod=freq / 120000u -1;
    uMod=50;
    TPM_BWR_MOD_MOD(tpmbase, uMod); //Sets the TPM peripheral timer modulo value

    //Setting up for Toggle output on Match on CS0SC
    //value=0x14u; //00010100 binary for Toggle Output on match where order of bits is: CHF CHIE MSB MSA ELSB ELSA 0 0
    value=0x28u; //00101000 binary for Edge-Aligned PWM where order of bits is: CHF CHIE MSB MSA ELSB ELSA 0 0
    TPM_WR_CnSC(tpmbase,0,value); //The CnSC register needs to be written all at once!

    //Set the Timer Channel Count Value for PWM
    uCnV=uMod * 50/100; //sets the count value to be the PWM duty cycle...x/100 is the duty cycle
    TPM_BWR_CnV_VAL(tpmbase, channel, uCnV); //Sets the TPM peripheral timer channel counter value

    //Set the Configuration registers
    TPM_BWR_CONF_TRGSEL(tpmbase, 1000);//Trigger Select for TPM0 overflow
    TPM_BWR_CONF_CROT(tpmbase, 0); //Counter reload on trigger rising edge, 1=enabled
    TPM_BWR_CONF_CSOO(tpmbase,0); //Counter stop on overflow, 1=enabled
    TPM_BWR_CONF_CSOT(tpmbase, 0); //Counter start immediately once enabled
    TPM_BWR_CONF_GTBEEN(tpmbase, 0); //Global time base enable, 0=all channels use internal TPM counter as timebase
    TPM_BWR_CONF_DBGMODE(tpmbase, 00); //Debug mode, set to have counter continue working in debug mode


    TPM_BWR_CnSC_CHIE(tpmbase,0,1); //Enable interrupts
    TPM_BWR_SC_TOIE(tpmbase, 1); //Enable the Timer overflow interrupt
    TPM_BWR_SC_TOF(tpmbase, 1);//Clear the TOF field (timer overflow)
    TPM_BWR_SC_CMOD(tpmbase, 01); //Start the counter. Set the TPM counter clock mode to increment on every TPM counter clock

    //Interrupt stuff
    NVIC_ClearPendingIRQ(g_tpmIrqId[instance]);
    //INT_SYS_InstallHandler ( TPM0_IRQn, *TPM0_IRQHandler );
    INT_SYS_EnableIRQ(TPM0_IRQn);
   // INT_SYS_EnableIRQGlobal;

    while(1){}
}

void TPM0_IRQHandler(void)
{
    TPM_Type *tpmbase=g_tpmBase[BOARD_TPM_INSTANCE];
    LED3_EN;
    LED3_ON;
    LED3_OFF;
    LED3_DIS;
    PRINTF("\r\nRunning the SaraTMRINT project: This is the interrupt\r\n");

    TPM_WR_STATUS(tpmbase, 1); //Clear the entire interrupt flags

}

Labels (1)
0 Kudos
1 Solution
1,223 Views
mjbcswitzerland
Specialist V

Hi

I attached an interrupt handling example to the previous post.

Here it a copy of what you are probably most interest in (FlexTimer and TPU are compatible here so don't get worried about the names):


// Generic interrupt handling
//
static void fnHandleFlexTimer(FLEX_TIMER_MODULE *ptrFlexTimer, int iFlexTimerReference)
{
    if ((ptrFlexTimer->FTM_SC & FTM_SC_TOF) != 0) { // flag will always be set but it has to be read at '1' before it can be reset
        if (usFlexTimerMode[iFlexTimerReference] & FLEX_TIMER_PERIODIC) {// if the timer is being used in periodic mode
            ptrFlexTimer->FTM_SC = (usFlexTimerMode[iFlexTimerReference] & FTM_SC_USED_MASK); // reset interrupt and allow the FlexTimer to continue running for periodic interrupts
        }
        else {
            ptrFlexTimer->FTM_SC = FTM_SC_TOF; // stop further activity (single-shot mode)
            switch (iFlexTimerReference) { // power down the FlexTimer after single-shot use
            case 0:
                POWER_DOWN(6, SIM_SCGC6_FTM0);
                break;
            case 1:
                POWER_DOWN(6, SIM_SCGC6_FTM1);
                break;
            }
        }
    }
    if (_flexTimerHandler[iFlexTimerReference] != 0) {                   // if there is a user handler
        uDisable_Interrupt();
            _flexTimerHandler[iFlexTimerReference]();                    // call user handler
        uEnable_Interrupt();
    }
}

Even if you need to stick with the solution you now use you can still simply run the open source uTasker KL03 project in KDS (which you already know) or in VisualStudio (massively more efficient for professional developers) to solve the present issues. It allows KL03 simulation so you can test and debug the operation most efficiently.

Half a day learning the uTasker basics would probably allow you to cut your further development time in half quite easily but it is up to you to decide whether this would be of any advantage for your work or whether you are already satisfied with the speed of project developments.

Regards

Mark

View solution in original post

0 Kudos
3 Replies
1,222 Views
mjbcswitzerland
Specialist V

Hi

References:
http://www.utasker.com/kinetis/FRDM-KL03Z.html
http://www.utasker.com/docs/uTasker/uTaskerHWTimers.PDF

To clear the interrupt you need to write the 0x80 flag in the control and status register - however ensure to preserve the other bits since they define its operation.

Attached is the FlexTimer/TPM driver for the uTasker project as reference and the simulation below - D4 is a RGB LED so it is normal that it is green if the green element is lit.

To save time use the uTasker open source KL03 project since it includes everything you need, is documented and allows you to develop, test and debug much easier and faster in its KL03 simulator.
Full opens source code at http://www.utasker.com/forum/index.php?topic=1721.msg7086#msg7086

Regards

Mark

pastedImage_1.png

0 Kudos
1,222 Views
sarastout-grand
Contributor III

Hi Mark,

Thanks, but I’ve invested time in learning the KDS and KDSK environments and don’t want to learn a new one right now.

Do you have any TPM interrupt documentation for KDSK? An example of would be great. Specifically, I want to see the interrupt subroutine.

Thanks,

Sara

Sara Stout-Grandy, M.Eng., Ph.D., P.Eng.

Senior Hardware Designer

20 Angus Morton Dr., Bedford,

NS, Canada, B4B 0L9

902-450-1700, x278

0 Kudos
1,224 Views
mjbcswitzerland
Specialist V

Hi

I attached an interrupt handling example to the previous post.

Here it a copy of what you are probably most interest in (FlexTimer and TPU are compatible here so don't get worried about the names):


// Generic interrupt handling
//
static void fnHandleFlexTimer(FLEX_TIMER_MODULE *ptrFlexTimer, int iFlexTimerReference)
{
    if ((ptrFlexTimer->FTM_SC & FTM_SC_TOF) != 0) { // flag will always be set but it has to be read at '1' before it can be reset
        if (usFlexTimerMode[iFlexTimerReference] & FLEX_TIMER_PERIODIC) {// if the timer is being used in periodic mode
            ptrFlexTimer->FTM_SC = (usFlexTimerMode[iFlexTimerReference] & FTM_SC_USED_MASK); // reset interrupt and allow the FlexTimer to continue running for periodic interrupts
        }
        else {
            ptrFlexTimer->FTM_SC = FTM_SC_TOF; // stop further activity (single-shot mode)
            switch (iFlexTimerReference) { // power down the FlexTimer after single-shot use
            case 0:
                POWER_DOWN(6, SIM_SCGC6_FTM0);
                break;
            case 1:
                POWER_DOWN(6, SIM_SCGC6_FTM1);
                break;
            }
        }
    }
    if (_flexTimerHandler[iFlexTimerReference] != 0) {                   // if there is a user handler
        uDisable_Interrupt();
            _flexTimerHandler[iFlexTimerReference]();                    // call user handler
        uEnable_Interrupt();
    }
}

Even if you need to stick with the solution you now use you can still simply run the open source uTasker KL03 project in KDS (which you already know) or in VisualStudio (massively more efficient for professional developers) to solve the present issues. It allows KL03 simulation so you can test and debug the operation most efficiently.

Half a day learning the uTasker basics would probably allow you to cut your further development time in half quite easily but it is up to you to decide whether this would be of any advantage for your work or whether you are already satisfied with the speed of project developments.

Regards

Mark

0 Kudos