This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Interrupt problems

Hi!

 

First of all, I'm very new to the TI Stellaris boards. I'm trying to read out a produced PWM signal. I am using a EK-LM3S9B90 eva Board.

 

So, here is my code. As you can see, I have no idea how to get to the width of the PWM signal peak. I expect a peak of about 1ms width (which should be calculated in the code) and a period of 20ms const.

 

Is there a possibility to read out the point where the interrupts on both edges are called and write them into variables? So it should be easy to get the pulse width, as I think... This may sound dumb, but my programming skills are in their infant stadium.

 

Help is much appreciated!

void
SetPins(void) // I/O Pins Konfigurieren
{
    // GPIO Port D aktivieren
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE);

    // GPIO Port D, Pin 4 als CCP (Capture Compare PWM) genutzt
    GPIOPinConfigure(GPIO_PD4_CCP3);
    // GPIO Port D, Pin 3 als CCP für PWM-Auslesen mittel Capture
    GPIOPinConfigure(GPIO_PE3_CCP1);

    // Settings für CCP Pins. Nötig für Timer/PWM
    GPIOPinTypeTimer(GPIO_PORTD_BASE, GPIO_PIN_4);
    GPIOPinTypeTimer(GPIO_PORTE_BASE, GPIO_PIN_3);

    // USR_LED ausschalten
    GPIOPinWrite(GPIO_PORTD_BASE, GPIO_PIN_0, 0);
}


void
InitConsole(void) // UART Initialisieren
{
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);

    GPIOPinConfigure(GPIO_PA0_U0RX);
    GPIOPinConfigure(GPIO_PA1_U0TX);

    GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);

    UARTStdioInit(0);
}

/*
void
Timer0BIntHandler(void) // Timer0B Handler für Capture INTs
{
	// Timer INT Flag löschen
	TimerIntClear(TIMER0_BASE, TIMER_TIMB_TIMEOUT);

	//if()

	IntDisable(INT_TIMER0B); // INT deaktivieren
	TimerIntDisable(TIMER0_BASE, TIMER_TIMB_TIMEOUT); // INT verbieten
	TimerIntClear(TIMER0_BASE, TIMER_TIMB_TIMEOUT); // offene Flags löschen
}
*/

int
main(void)
{
    SysCtlClockSet(SYSCTL_SYSDIV_1 | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN |
    			   SYSCTL_XTAL_16MHZ);

    // Aktivierung Timer
    SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER1);

    SetPins();
    InitConsole();

    // Timerkonfigurierung
    TimerConfigure(TIMER0_BASE, TIMER_CFG_B_CAP_COUNT_UP);
    TimerConfigure(TIMER1_BASE, TIMER_CFG_16_BIT_PAIR |
    			   TIMER_CFG_B_PWM);

    // 5% Duty Cycle für PWM
    TimerLoadSet(TIMER1_BASE, TIMER_B, 64000);
    TimerMatchSet(TIMER1_BASE, TIMER_B, TimerLoadGet(TIMER1_BASE, TIMER_B) - 3200);

    // bei Peak an CCP1 INT auslösen
    TimerControlEvent(TIMER0_BASE, TIMER_B, TIMER_EVENT_BOTH_EDGES);

    // Timer einschalten
    TimerEnable(TIMER0_BASE, TIMER_B);
    TimerEnable(TIMER1_BASE, TIMER_B);

    // Clearen und Erlauben des TimerINT
    TimerIntClear(TIMER0_BASE, TIMER_CAPA_EVENT | TIMER_CAPB_EVENT);
    TimerIntEnable(TIMER0_BASE, TIMER_CAPA_EVENT | TIMER_CAPB_EVENT);

    // INTs erlauben (vgl. sei())
    IntMasterEnable();

    PeakTime = ???;
    UARTprintf("Breite Peak: %d\n", PeakTime); // Breite Peak als Zählerstand Timer
    PeakTime = 0;

    while(1)
    {

    }
}


  • Hello Alex,

    Yes, the timer in Input Edge Time Mode can be used to capture the time at which the last edge occurred. The code has to read the GPTMTAR or GPTMTBR register to get the information

    Regards

    Amit

  • Hello Amit,


    thanks for replying. So you think my code is correct except for the reading of registers and calculation?

    bw

    Alex

  • Hello Alex,

    Are you using TIVAWare or StellarisWare. There are some defines I do not see in TIVAWare. Also which version of TIVAWare are you using?

    Regards

    Amit

  • I am using StellarisWare. I actually don't know which version. I'm very new to the TI world

    Ah, and i did not copy the includes, sorry!

    //#include <inc/lm3s9b90.h>
    #include <inc/hw_memmap.h>
    #include <inc/hw_types.h>
    #include <inc/hw_timer.h>
    #include <inc/hw_ints.h>
    #include <inc/hw_gpio.h>
    #include <driverlib/debug.h>
    #include <driverlib/timer.h>
    #include <driverlib/interrupt.h>
    #include <driverlib/sysctl.h>
    #include <driverlib/gpio.h>
    #include <utils/uartstdio.h>

    bw

    Alex

  • Hello Alex

    LM3S is NRND so it will take me some time to get the SW version and check the code. I hope it is OK

    Regards

    Amit

  • No worries. I got the code working with TimerValueGet from both TimerA and TimerB. But I think my code in main is in wrong order. Because the timer values seem a bit random, apart that it delivers a negative value.


    Here's the new code. The voids are the same, just the main has changed:

    int
    main(void)
    {
        SysCtlClockSet(SYSCTL_SYSDIV_1 | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN |
        			   SYSCTL_XTAL_16MHZ);
    
        // Aktivierung Timer
        SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);
        SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER1);
    
        SetPins();
        InitConsole();
    
        // Timerkonfigurierung
        TimerConfigure(TIMER0_BASE, TIMER_CFG_A_CAP_COUNT_UP);
        TimerConfigure(TIMER0_BASE, TIMER_CFG_B_CAP_COUNT_UP);
        TimerConfigure(TIMER1_BASE, TIMER_CFG_16_BIT_PAIR |
        			   TIMER_CFG_B_PWM);
    
        // 5% Duty Cycle für PWM
        TimerLoadSet(TIMER1_BASE, TIMER_B, 64000);
        TimerMatchSet(TIMER1_BASE, TIMER_B, TimerLoadGet(TIMER1_BASE, TIMER_B) - 3200);
    
        // bei Peak an CCP1 INT auslösen
        //TimerControlEvent(TIMER0_BASE, TIMER_B, TIMER_EVENT_BOTH_EDGES);
        TimerControlEvent(TIMER0_BASE, TIMER_A, TIMER_EVENT_POS_EDGE);
        TimerControlEvent(TIMER0_BASE, TIMER_B, TIMER_EVENT_NEG_EDGE);
        //GPIOIntTypeSet(GPIO_PORTE_BASE, GPIO_PIN_3, GPIO_BOTH_EDGES);
        //GPIOPinIntEnable(GPIO_PORTE_BASE, GPIO_PIN_3);
    
        // Timer einschalten
        TimerEnable(TIMER1_BASE, TIMER_B);
        TimerEnable(TIMER0_BASE, TIMER_A);
        TimerEnable(TIMER0_BASE, TIMER_B);
    
        // Clearen und Erlauben des Timer0 INT
        TimerIntClear(TIMER0_BASE, TIMER_CAPA_EVENT | TIMER_CAPB_EVENT);
        TimerIntEnable(TIMER0_BASE, TIMER_CAPA_EVENT | TIMER_CAPB_EVENT);
        TimerIntClear(TIMER0_BASE, TIMER_CAPA_EVENT | TIMER_CAPB_EVENT);
        TimerIntEnable(TIMER0_BASE, TIMER_CAPA_EVENT | TIMER_CAPB_EVENT);
    
        // INTs erlauben (vgl. sei())
        IntMasterEnable();
    
        PosEdge = TimerValueGet(TIMER0_BASE, TIMER_A);
        NegEdge = TimerValueGet(TIMER0_BASE, TIMER_B);
        PeakTime = NegEdge - PosEdge;
        UARTprintf("Breite Peak: %d Zählerticks\n", PeakTime); // Breite Peak als Zählerstand Timer
        PeakTime = 0;
    
        while(1)
        {
    
        }
    }

  • Hello Alex,

    The negative value would be arising if the rollover of the timer for latter edge has occurred and the previous edge was before the rollover.

    Regards

    Amit

  • I'm not quite sure if I can follow you right. A captures pos edges (rising) and B the neg edges (falling), don't they? So, when I substract Bvalue from Avalue i should get the amount of timerticks for the pulse, or am I wrong?

        PosEdge = TimerValueGet(TIMER0_BASE, TIMER_A);
        NegEdge = TimerValueGet(TIMER0_BASE, TIMER_B);
        PeakTime = NegEdge - PosEdge;

    was the old eq.

    now I have:

        PeakTime = TimerValueGet(TIMER0_BASE, TIMER_A) - TimerValueGet(TIMER0_BASE, TIMER_B);


    which delivers completely different values. I am confused...

  • Hello Alex,

    Firstly, The capture have to be done in the Interrupt Handler for each timer A and B

    Secondly, consider timer A capturing the Pos Edge close to the Roll Over from 0xFFFF to 0x0 and timer B capture after roll over/ Thus the PosEdge will be larger than NegEdge even though they absolute value may be correct, the subtraction will yield a -ve result.

    Regards

    Amit

  • Do you maybe have an example code for such an application? The example codes for timers in my StellarisWare are not quite helping.

    What must be in the IntHandler and what in the main?


    My pwm generation for testing purposes works fine, without an Interrupt handler. Or is for this function none necessary?


    Thanks again for your time!

  • Hello Alex,

    I do not have a code example either.

    The place where the code reads the TimerValue should be in the respective Interrupt Handler. Timer A read should be in Timer A Interrupt Handler and Timer B should be in Timer B Interrupt Handler.

    In the main the computation should be done when both interrupt are fired

    E.g.

    while(10 {

     if(PosEdge == true && NegEdge == true) {

      Timer = PoseEdgeVal - NegEdgeVal;

      PosEdge = false;

      NegEdge = false;

     }

    }

    The flags should be set true in the respective Interrupt Handler.

    Regards

    Amit

  • Thank you for that. But when I use Timer0 A and B, I have two IntHandler, one for each as you said.

    So, just to recapitulate:
     I only get an INT when I have an IntHandler. So I can only read a timer value at this precise time in the handler itself, am I right?

    So for my particular case: I have two handlers, so I need to write the values in a variable in each IntHandler and can process it further later on in the main?

  • Hello Alex,

    The INT is generated when the correct IM bits are set and the Interrupt enabled in the NVIC. The IntHandler is the mechanism by which the code processes the interrupt.

    Rest of the post looks correct.

    Regards

    Amit

  • So, do I have to manipulate the registers now?

    Here's my most actual code snippet, which still doesn't work. I think the IntHandlers are still wrong

    void
    Timer0AIntHandler(void)
    {
        TimerIntClear(TIMER0_BASE, TIMER_CAPA_EVENT | TIMER_CAPB_EVENT);
    
       	if(PosEdge == true)
       	{
       		PeakTime = TimerValueGet(TIMER0_BASE, TIMER_A);
       	}
    
    
        //g_ulIntCounterA++;
    }
    
    void
    Timer0BIntHandler(void)
    {
        TimerIntClear(TIMER0_BASE, TIMER_CAPA_EVENT | TIMER_CAPB_EVENT);
    
    
       	if(NegEdge == true)
       	{
       		PeakTime = TimerValueGet(TIMER0_BASE, TIMER_B);
       	}
    
    
        //g_ulIntCounterB++;
    }
    
    
    int
    main(void)
    {
        SysCtlClockSet(SYSCTL_SYSDIV_1 | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN |
        			   SYSCTL_XTAL_16MHZ);
    
        // Aktivierung Timer
        SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);
        SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER1);
    
        SetPins();
        InitConsole();
    
        // Timerkonfigurierung
        TimerConfigure(TIMER0_BASE, TIMER_CFG_A_CAP_COUNT_UP);
        TimerConfigure(TIMER0_BASE, TIMER_CFG_B_CAP_COUNT_UP);
        TimerConfigure(TIMER1_BASE, TIMER_CFG_16_BIT_PAIR |
        			   TIMER_CFG_B_PWM);
    
        // 5% Duty Cycle für PWM
        TimerLoadSet(TIMER1_BASE, TIMER_B, 64000);
        TimerMatchSet(TIMER1_BASE, TIMER_B, TimerLoadGet(TIMER1_BASE, TIMER_B) - 3200);
    
        // INTs erlauben (vgl. sei())
        IntMasterEnable();
    
        TimerControlEvent(TIMER0_BASE, TIMER_A, TIMER_EVENT_POS_EDGE);
        TimerControlEvent(TIMER0_BASE, TIMER_B, TIMER_EVENT_NEG_EDGE);
    
        TimerIntEnable(TIMER0_BASE, TIMER_CAPA_EVENT | TIMER_CAPB_EVENT);
        TimerIntEnable(TIMER0_BASE, TIMER_CAPA_EVENT | TIMER_CAPB_EVENT);
    
        IntEnable(INT_TIMER0A);
        IntEnable(INT_TIMER0B);
    
        // Timer einschalten
        TimerEnable(TIMER1_BASE, TIMER_B);
        TimerEnable(TIMER0_BASE, TIMER_A);
        TimerEnable(TIMER0_BASE, TIMER_B);
    
    
        //PosEdge = TimerValueGet(TIMER0_BASE, TIMER_A);
        //NegEdge = TimerValueGet(TIMER0_BASE, TIMER_B);
        //PeakTime = NegEdge - PosEdge;
        //PeakTime = TimerValueGet(TIMER0_BASE, TIMER_A) - TimerValueGet(TIMER0_BASE, TIMER_B);
        UARTprintf("Zählerstand 0A: %d\n", PosEdge);
        UARTprintf("Zählerstand 0B: %d\n", NegEdge);
        UARTprintf("\n");
        //UARTprintf("Breite Peak: %d\n", PeakTime); // Breite Peak als Zählerstand Timer
        //PeakTime = 0;
    
        while(1)
        {
        }
    }

  • Hello Alex

    void Timer0AIntHandler(void) { TimerIntClear(TIMER0_BASE, TIMER_CAPA_EVENT | TIMER_CAPB_EVENT); PosTime = TimerValueGet(TIMER0_BASE, TIMER_A);
    PosEdge = true;
    } 
    void Timer0BIntHandler(void) {
    TimerIntClear(TIMER0_BASE, TIMER_CAPA_EVENT | TIMER_CAPB_EVENT);
    NegTime = TimerValueGet(TIMER0_BASE, TIMER_B);NegEdge = true;
    NegEdge = true;
    }

    and in the main code

    while(1) {
    if(PosEdge == true and NegEdge == true) {
    UARTprintf("Value = %d", (PosTime-NegTime))'
    PosEdge = false;
    NegEdge = false;
    }
    }

    Regards
    Amit
  • Ah ok. I think I'm getting it slowly.

    Fixed all your suggestions and made the declarations but it doesn't work. There is no UART output.

  • Hello Alex

    Did you check the following

    1. The UART TX lines are toggling when you write to the UART Data Register through the debugger?

    2. Is there a jumper on the board which is missing that would connect the UART to the ICDI board?

    Regards

    Amit

  • Alex M. said:
    Is there a possibility to read out the point where the interrupts on both edges are called and write them into variables? So it should be easy to get the pulse width, as I think... This may sound dumb, but my programming skills are in their infant stadium.

    @Amit. I am not an expert with this. But, I see at the Drivers Library User's Guide for a parameter "TIMER_BOTH". Might setting this at his Timer C API's, achieve his intended result?

    -kel

  • Hello Kel

    This is LM3S platform using StellarisWare. So some of the defines may be different

    Regards

    Amit