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.

TM4C1294NCPDT: TI-RTOS for TIVA c question

Part Number: TM4C1294NCPDT

Hello, 

    Im using a timer interrupt for a loop that checks for an event.  When that event is detected id like to stop the timer. 

when i call the Timer_stop() func it does indeed stop but there is a delay from the call to the actual stop ( i think) docsd on this are pretty cryptic. 

Is there a way to check when the timer actually stops?  I find it continues to recieve events after the stop call. If a delay is added it seems to work but i hate to just add 

some random delay if there was a way to know when the timer stops. 

Thanks

  • Hi,

    when i call the Timer_stop() func it does indeed stop but there is a delay from the call to the actual stop ( i think) docsd on this are pretty cryptic. 

    Is there a way to check when the timer actually stops?  I find it continues to recieve events after the stop call.

    After Timer_stop() is called, it will eventually write to the timer control register to disable the timer. I single step the disassembly code from Timer_stop() is called until the STR instruction is executed, there are a few instructions to go through. Please look at the callstack below. I counted about 18 instructions before STR is executed. Eventually the TIMER_CTL register bit 0 (TAEN) is cleared to stop the timer. I use Timer2A for this experiment. 

    If a delay is added it seems to work but i hate to just add 

    some random delay if there was a way to know when the timer stops. 

    I don't understand this part. What do you mean to add delay? Why is this needed? How is that event generated? What is the priority of that event? Is it possible that that event has higher priority than the task that calls Timer_stop(). In another word, the task which generates the event preempts the task that calls Timer_stop() due to its higher priority?

  • thank you for the response. I am trying to debounce a switch by using a timer interrupt. like polling. after the debounce , which does work quite well, I want to then measure the duration of the button press. I thought if I could stop the timer interrupt it would be easy to get the time from press to release. 

    thanks again 

  • Hi Patrick,

      The interrupt which is managed as Hwi will have higher priority than a task. What might have happened is that the bouncing switch will create multiple interrupts in short duration that can preempt the task from disabling the timer. Even if the timer is disabled, the bouncing can continue to occur. 

      Please take a look at the below code that implements a simple software debounce. Although this is written for FreeRTOS, you can use the same idea for TI-RTOS. Look at vSW1Handler where it de-bounces the switch with a 200ms software filter.  

    /* Standard includes. */
    #include <stdio.h>
    #include <stdint.h>
    #include <stdbool.h>
    
    /* Kernel includes. */
    #include "FreeRTOS.h"
    #include "task.h"
    #include "semphr.h"
    
    /* Hardware includes. */
    #include "inc/hw_ints.h"
    #include "inc/hw_memmap.h"
    #include "driverlib/gpio.h"
    #include "driverlib/interrupt.h"
    #include "driverlib/sysctl.h"
    #include "drivers/rtos_hw_drivers.h"
    #include "utils/uartstdio.h"
    
    
    /* Priorities at which the tasks are created. */
    #define mainSEMAPHORE_TASK_PRIORITY     ( tskIDLE_PRIORITY + 1 )
    
    /* The semaphore used by both tasks. */
    SemaphoreHandle_t ButtonIntSemaphore;
    
    /*-----------------------------------------------------------*/
    /*
     * The tasks as described in the comments at the top of this file.
     */
    static void prvTaskLedon( void *pvParameters );
    static void prvTaskLedoff( void *pvParameters );
    
    /* Time Stamp variable */
    uint32_t g_ui32preTimeStamp;
    
    /*
     * Called by main() to create the simply blinky style application
     */
    void vBlinkyTask( void );
    
    /* 
     * Configure a button to generate interrupts
     */
    static void prvConfigureButton( void );
    
    /*-----------------------------------------------------------*/
    
    /* Called by main() to create the simply blinky style application */
    
    void vBlinkyTask( void )
    {
        /* Configure a button to generate interrupts. */
    	prvConfigureButton();
    
        /* Create a binary semaphore. */
        ButtonIntSemaphore = xSemaphoreCreateBinary();
    
        if( ButtonIntSemaphore != NULL )
        {
            /* Start the two tasks as described in the comments at the top of this
            file. */
            xTaskCreate(prvTaskLedon,                      /* The function to turn ON LED */
                        "Ledon",                           /* The text name assigned to the task. */
                        configMINIMAL_STACK_SIZE,          /* The size of the stack to allocate to the task. */
                        NULL,                              /* No parameter passed to the task */
                        mainSEMAPHORE_TASK_PRIORITY ,      /* The priority assigned to the task. */
                        NULL );                            /* The task handle is not required, so NULL is passed. */
    
             xTaskCreate(prvTaskLedoff,                    /* The function to turn OFF LED */
                        "Ledoff",                          /* The text name assigned to the task. */
                        configMINIMAL_STACK_SIZE,          /* The size of the stack to allocate to the task. */
                        NULL,                              /* The priority assigned to the task. */
                        mainSEMAPHORE_TASK_PRIORITY,       /* The task handle is not required, so NULL is passed. */
                        NULL );
    	}
    }
    /*-----------------------------------------------------------*/
    
    /*
     * Task to turn ON LEDs
     */
    static void prvTaskLedon( void *pvParameters )
    {
        (void) pvParameters;
        uint32_t counter = 0;
    
        while (1)
        {
            if (xSemaphoreTake(ButtonIntSemaphore, portMAX_DELAY) == pdPASS)
            {
                UARTprintf("Turn on LED\n");
                if (counter % 3 == 0)
                {
                    LEDWrite(BLUE_LED|RED_LED|GREEN_LED, BLUE_LED);
                }
                else if (counter % 3 == 1)
                {
                    LEDWrite(BLUE_LED|RED_LED|GREEN_LED, RED_LED);
                }
                else if (counter % 3 == 2)
                {
                    LEDWrite(BLUE_LED|RED_LED|GREEN_LED, GREEN_LED);
                }
                counter++;
            }
        }
    }
    /*-----------------------------------------------------------*/
    
    /*
     * Task to turn OFF LEDs
     */
    static void prvTaskLedoff( void *pvParameters )
    {
        (void) pvParameters;
    
        while (1)
        {
            if (xSemaphoreTake(ButtonIntSemaphore, portMAX_DELAY) == pdPASS)
            {
                UARTprintf("Turn off LED\n");
                LEDWrite(BLUE_LED|RED_LED|GREEN_LED, 0);
            }
    
        }
    }
    /*-----------------------------------------------------------*/
    
    static void prvConfigureButton( void )
    {
        /* Configure buttona SW1 and SW2 to generate interrupts. */
    
        /* Initialize the LaunchPad Buttons. */
        ButtonsInit();
    
        /* Configure both switches to trigger an interrupt on a falling edge. */
        GPIOIntTypeSet(BUTTONS_GPIO_BASE, ALL_BUTTONS, GPIO_FALLING_EDGE);
    
        /* Enable the interrupt for Port J in the GPIO peripheral. */
        GPIOIntEnable(BUTTONS_GPIO_BASE, ALL_BUTTONS);
    
        /* Enable the Port J interrupt in the NVIC. */
        IntEnable(INT_GPIOF);
    
        /* Enable global interrupts in the NVIC. */
        IntMasterEnable();
    }
    /*-----------------------------------------------------------*/
    
    void vSW1Handler( void )
    {
    uint32_t ui32Status;
    BaseType_t  xHigherPriorityTaskWoken = pdFALSE;
    
        /* Read the Port J interrupt status to find the cause of the interrupt. */
        ui32Status = GPIOIntStatus(BUTTONS_GPIO_BASE, true);
    
    	/* Clear the interrupt. */
        GPIOIntClear(BUTTONS_GPIO_BASE, ui32Status);
    
        /* Debounce the input with 200ms filter */
        if ((xTaskGetTickCount() - g_ui32preTimeStamp ) > 200)
        {
            UARTprintf("Semaphore is given\n");
            xSemaphoreGiveFromISR(ButtonIntSemaphore, &xHigherPriorityTaskWoken);
        }
    
        g_ui32preTimeStamp = xTaskGetTickCount();
    
    
    }
    /*-----------------------------------------------------------*/
    
    void vApplicationTickHook( void )
    {
        /* This function will be called by each tick interrupt if
    		configUSE_TICK_HOOK is set to 1 in FreeRTOSConfig.h.  User code can be
    		added here, but the tick hook is called from an interrupt context, so
    		code must not attempt to block, and only the interrupt safe FreeRTOS API
    		functions can be used (those that end in FromISR()). */
    
        /* Only the full demo uses the tick hook so there is no code is
    		executed here. */
    }

  • the debounce part of the code is working just fine. what im stumbling on is trying to discern the length of the button push. 

    the Timer interrupt fires a function the does the debounce and posts a SWI to indicate a button press. This is then processed by a func that runs when the SWI is posted. 

    the issue im having is that the timer keeps running so if the button is held down it registers as a button push again. 

    I think I will have to modify the SWI func to recognize the button release also. 

    Thanks for you help 

  • How accurately/precisely do you need the button press duration?

    I would be inclined to have a simple low priority task to read the buttons, and just loop polling the button GPIO:

    while(true)

    {

        task_sleep(a few ms);

        read_button_gpio();

        process_changes();

    }

    If the sleep period is longer than the bounce duration, your debounce is done. The button press duration is just a count of the number of passes with the button pressed. Use a signal or a semaphore to tell other tasks about button presses and releases.

    This avoids extra interrupts and messing with timers. Slight smile

  • thanks jim.  I will give that a go . elegant solution