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 priority in tiva c: tm4c123gxl; how do i allot priority dynamically?



Hi,

So my two tasks are:

1. Setting up a square wave using interrupts. 

2. Check ADC values every 10 seconds

In case I give the square wave 1st priority, there should be no distortion in the square wave; but at the same time will I be able to check ADC values every 10 seconds, will it even go to the 2nd task? I am using API(s).

Thank you

  • Hello Kirthi

    Why us a interrupt to generate the output when timer in PWM mode can do the same without having to raise additional interrupts.

    Normally the task of interrupt entry and exit is 14-18 clock cycles + processing time in the interrupt handler, that it will not cause an issue for tasks at 10 sec intervals.
  • Amit is correct on both points. A hardware approach usually removes concerns about timing and a 10s task is generally not disturbed by a sub-second task. The issue is generally whether the first task will be a high enough priority to interrupt the second, it usually must be in order to meet it's timing requirements. As long is that is the case it should be fine if nether task exceeds their allotted time and the higher priority tasks leave time for the lower priority tasks. Basically the higher priority tasks act as if they are slowing the processor as far as the lower priority tasks are concerned.

    There is, however, a more general approach to the issue. Find some references to Rate Monotonic Analysis (RMA). Basically, higher frequency tasks are higher priority.

    Robert
  • Ok, I am just experimenting with these interrupts and I want to get more resolute about the interrupts and timer concepts.

    Should I use the fucntion IntPrioritySet ? in order to give the tasks priority?

    I want the square wave to run for an infinite time, and the ADC should check values every 10 seconds, if I give them both same priority; basically the ADC should distort the square wave and I want to calculate the time ADC takes to sample the data.

    How should I go about it:?

  • Hello Kirthi,

    As explained by me and Robert, why not offload the "Square wave generation" to a timer running in PWM mode. That ways the PWM shall always be a square wave and not require any specific interrupt processing.
  • What is your goal Kirthi?

    Do you want to finish the task you've outlined?
    Or do you want to learn about scheduling real time tasks? If this is what your goal is outline what your approach is now. Maybe show some pseudo-code.

    Robert
  • Hello Robert,

    I don't think the O.P. is using "tasks" in sense of a RTOS.
  • Agreed Amit, but whether you're scheduling a full blown RTOS or just a few interrupts the basic concepts are identical

    Robert
  • Hello Robert

    Agreed. The concept remains the same.
  • //*****************************************************************************
    //
    // interrupts.c - Interrupt preemption and tail-chaining example.
    //
    // Copyright (c) 2012-2016 Texas Instruments Incorporated.  All rights reserved.
    // Software License Agreement
    // 
    // Texas Instruments (TI) is supplying this software for use solely and
    // exclusively on TI's microcontroller products. The software is owned by
    // TI and/or its suppliers, and is protected under applicable copyright
    // laws. You may not combine this software with "viral" open-source
    // software in order to form a larger program.
    // 
    // THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
    // NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
    // NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    // A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
    // CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
    // DAMAGES, FOR ANY REASON WHATSOEVER.
    // 
    // This is part of revision 2.1.3.156 of the EK-TM4C123GXL Firmware Package.
    //
    //*****************************************************************************
    
    #include <stdint.h>
    #include <stdbool.h>
    #include "inc/hw_ints.h"
    #include "inc/hw_memmap.h"
    #include "inc/hw_nvic.h"
    #include "inc/hw_types.h"
    #include "driverlib/debug.h"
    #include "driverlib/fpu.h"
    #include "driverlib/gpio.h"
    #include "driverlib/interrupt.h"
    #include "driverlib/pin_map.h"
    #include "driverlib/rom.h"
    #include "driverlib/sysctl.h"
    #include "driverlib/systick.h"
    #include "driverlib/uart.h"
    #include "utils/uartstdio.h"
    
    //*****************************************************************************
    //
    //! \addtogroup example_list
    //! <h1>Interrupts (interrupts)</h1>
    //!
    //! This example application demonstrates the interrupt preemption and
    //! tail-chaining capabilities of Cortex-M4 microprocessor and NVIC.  Nested
    //! interrupts are synthesized when the interrupts have the same priority,
    //! increasing priorities, and decreasing priorities.  With increasing
    //! priorities, preemption will occur; in the other two cases tail-chaining
    //! will occur.  The currently pending interrupts and the currently executing
    //! interrupt will be displayed on the display; GPIO pins E1, E2 and E3 will
    //! be asserted upon interrupt handler entry and de-asserted before interrupt
    //! handler exit so that the off-to-on time can be observed with a scope or
    //! logic analyzer to see the speed of tail-chaining (for the two cases where
    //! tail-chaining is occurring).
    //
    //*****************************************************************************
    
    //*****************************************************************************
    //
    // The count of interrupts received.  This is incremented as each interrupt
    // handler runs, and its value saved into interrupt handler specific values to
    // determine the order in which the interrupt handlers were executed.
    //
    //*****************************************************************************
    volatile uint32_t g_ui32Index;
    
    //*****************************************************************************
    //
    // The value of g_ui32Index when the INT_GPIOA interrupt was processed.
    //
    //*****************************************************************************
    volatile uint32_t g_ui32GPIOa;
    
    //*****************************************************************************
    //
    // The value of g_ui32Index when the INT_GPIOB interrupt was processed.
    //
    //*****************************************************************************
    volatile uint32_t g_ui32GPIOb;
    
    //*****************************************************************************
    //
    // The value of g_ui32Index when the INT_GPIOC interrupt was processed.
    //
    //*****************************************************************************
    volatile uint32_t g_ui32GPIOc;
    
    //*****************************************************************************
    //
    // The error routine that is called if the driver library encounters an error.
    //
    //*****************************************************************************
    #ifdef DEBUG
    void
    __error__(char *pcFilename, uint32_t ui32Line)
    {
    }
    #endif
    
    //*****************************************************************************
    //
    // Delay for the specified number of seconds.  Depending upon the current
    // SysTick value, the delay will be between N-1 and N seconds (i.e. N-1 full
    // seconds are guaranteed, aint32_t with the remainder of the current second).
    //
    //*****************************************************************************
    void
    Delay(uint32_t ui32Seconds)
    {
        //
        // Loop while there are more seconds to wait.
        //
        while(ui32Seconds--)
        {
            //
            // Wait until the SysTick value is less than 1000.
            //
            while(ROM_SysTickValueGet() > 1000)
            {
            }
    
            //
            // Wait until the SysTick value is greater than 1000.
            //
            while(ROM_SysTickValueGet() < 1000)
            {
            }
        }
    }
    
    //*****************************************************************************
    //
    // Display the interrupt state on the UART.  The currently active and pending
    // interrupts are displayed.
    //
    //*****************************************************************************
    void
    DisplayIntStatus(void)
    {
        uint32_t ui32Temp;
    
        //
        // Display the currently active interrupts.
        //
        ui32Temp = HWREG(NVIC_ACTIVE0);
        UARTprintf("\rActive: %c%c%c ", (ui32Temp & 1) ? '1' : ' ',
                   (ui32Temp & 2) ? '2' : ' ', (ui32Temp & 4) ? '3' : ' ');
    
        //
        // Display the currently pending interrupts.
        //
        ui32Temp = HWREG(NVIC_PEND0);
        UARTprintf("Pending: %c%c%c", (ui32Temp & 1) ? '1' : ' ',
                   (ui32Temp & 2) ? '2' : ' ', (ui32Temp & 4) ? '3' : ' ');
    }
    
    //*****************************************************************************
    //
    // This is the handler for INT_GPIOA.  It simply saves the interrupt sequence
    // number.
    //
    //*****************************************************************************
    void
    IntGPIOa(void)
    {
        //
        // Set PE1 high to indicate entry to this interrupt handler.
        //
        ROM_GPIOPinWrite(GPIO_PORTE_BASE, GPIO_PIN_1, GPIO_PIN_1);
    
        //
        // Put the current interrupt state on the UART.
        //
        DisplayIntStatus();
    
        //
        // Wait two seconds.
        //
        Delay(2);
    
        //
        // Save and increment the interrupt sequence number.
        //
        g_ui32GPIOa = g_ui32Index++;
    
        //
        // Set PE1 low to indicate exit from this interrupt handler.
        //
        ROM_GPIOPinWrite(GPIO_PORTE_BASE, GPIO_PIN_1, 0);
    }
    
    //*****************************************************************************
    //
    // This is the handler for INT_GPIOB.  It triggers INT_GPIOA and saves the
    // interrupt sequence number.
    //
    //*****************************************************************************
    void
    IntGPIOb(void)
    {
        //
        // Set PE2 high to indicate entry to this interrupt handler.
        //
        ROM_GPIOPinWrite(GPIO_PORTE_BASE, GPIO_PIN_2, GPIO_PIN_2);
    
        //
        // Put the current interrupt state on the UART.
        //
        DisplayIntStatus();
    
        //
        // Trigger the INT_GPIOA interrupt.
        //
        HWREG(NVIC_SW_TRIG) = INT_GPIOA - 16;
    
        //
        // Put the current interrupt state on the UART.
        //
        DisplayIntStatus();
    
        //
        // Wait two seconds.
        //
        Delay(2);
    
        //
        // Save and increment the interrupt sequence number.
        //
        g_ui32GPIOb = g_ui32Index++;
    
        //
        // Set PE2 low to indicate exit from this interrupt handler.
        //
        ROM_GPIOPinWrite(GPIO_PORTE_BASE, GPIO_PIN_2, 0);
    }
    
    //*****************************************************************************
    //
    // This is the handler for INT_GPIOC.  It triggers INT_GPIOB and saves the
    // interrupt sequence number.
    //
    //*****************************************************************************
    void
    IntGPIOc(void)
    {
        //
        // Set PE3 high to indicate entry to this interrupt handler.
        //
        ROM_GPIOPinWrite(GPIO_PORTE_BASE, GPIO_PIN_3, GPIO_PIN_3);
    
        //
        // Put the current interrupt state on the UART.
        //
        DisplayIntStatus();
    
        //
        // Trigger the INT_GPIOB interrupt.
        //
        HWREG(NVIC_SW_TRIG) = INT_GPIOB - 16;
    
        //
        // Put the current interrupt state on the UART.
        //
        DisplayIntStatus();
    
        //
        // Wait two seconds.
        //
        Delay(2);
    
        //
        // Save and increment the interrupt sequence number.
        //
        g_ui32GPIOc = g_ui32Index++;
    
        //
        // Set PE3 low to indicate exit from this interrupt handler.
        //
        ROM_GPIOPinWrite(GPIO_PORTE_BASE, GPIO_PIN_3, 0);
    }
    
    //*****************************************************************************
    //
    // Configure the UART and its pins.  This must be called before UARTprintf().
    //
    //*****************************************************************************
    void
    ConfigureUART(void)
    {
        //
        // Enable the GPIO Peripheral used by the UART.
        //
        ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
    
        //
        // Enable UART0
        //
        ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);
    
        //
        // Configure GPIO Pins for UART mode.
        //
        ROM_GPIOPinConfigure(GPIO_PA0_U0RX);
        ROM_GPIOPinConfigure(GPIO_PA1_U0TX);
        ROM_GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);
    
        //
        // Use the internal 16MHz oscillator as the UART clock source.
        //
        UARTClockSourceSet(UART0_BASE, UART_CLOCK_PIOSC);
    
        //
        // Initialize the UART for console I/O.
        //
        UARTStdioConfig(0, 115200, 16000000);
    }
    
    //*****************************************************************************
    //
    // This is the main example program.  It checks to see that the interrupts are
    // processed in the correct order when they have identical priorities,
    // increasing priorities, and decreasing priorities.  This exercises interrupt
    // preemption and tail chaining.
    //
    //*****************************************************************************
    int
    main(void)
    {
        uint32_t ui32Error;
    
        //
        // Enable lazy stacking for interrupt handlers.  This allows floating-point
        // instructions to be used within interrupt handlers, but at the expense of
        // extra stack usage.
        //
        ROM_FPULazyStackingEnable();
    
        //
        // Set the clocking to run directly from the crystal.
        //
        ROM_SysCtlClockSet(SYSCTL_SYSDIV_1 | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN |
                           SYSCTL_XTAL_16MHZ);
    
        //
        // Enable the peripherals used by this example.
        //
        ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE);
    
        //
        // Initialize the UART.
        //
        ConfigureUART();
    
        UARTprintf("\033[2JInterrupts\n");
    
        //
        // Configure the PB0-PB2 to be outputs to indicate entry/exit of one
        // of the interrupt handlers.
        //
        ROM_GPIOPinTypeGPIOOutput(GPIO_PORTE_BASE, GPIO_PIN_1 | GPIO_PIN_2 |
                                                   GPIO_PIN_3);
        ROM_GPIOPinWrite(GPIO_PORTE_BASE, GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3, 0);
    
        //
        // Set up and enable the SysTick timer.  It will be used as a reference
        // for delay loops in the interrupt handlers.  The SysTick timer period
        // will be set up for one second.
        //
        ROM_SysTickPeriodSet(ROM_SysCtlClockGet());
        ROM_SysTickEnable();
    
        //
        // Reset the error indicator.
        //
        ui32Error = 0;
    
        //
        // Enable interrupts to the processor.
        //
        ROM_IntMasterEnable();
    
        //
        // Enable the interrupts.
        //
        ROM_IntEnable(INT_GPIOA);
        ROM_IntEnable(INT_GPIOB);
        ROM_IntEnable(INT_GPIOC);
    
        //
        // Indicate that the equal interrupt priority test is beginning.
        //
        UARTprintf("\nEqual Priority\n");
    
        //
        // Set the interrupt priorities so they are all equal.
        //
        ROM_IntPrioritySet(INT_GPIOA, 0x00);
        ROM_IntPrioritySet(INT_GPIOB, 0x00);
        ROM_IntPrioritySet(INT_GPIOC, 0x00);
    
        //
        // Reset the interrupt flags.
        //
        g_ui32GPIOa = 0;
        g_ui32GPIOb = 0;
        g_ui32GPIOc = 0;
        g_ui32Index = 1;
    
        //
        // Trigger the interrupt for GPIO C.
        //
        HWREG(NVIC_SW_TRIG) = INT_GPIOC - 16;
    
        //
        // Put the current interrupt state on the LCD.
        //
        DisplayIntStatus();
    
        //
        // Verify that the interrupts were processed in the correct order.
        //
        if((g_ui32GPIOa != 3) || (g_ui32GPIOb != 2) || (g_ui32GPIOc != 1))
        {
            ui32Error |= 1;
        }
    
        //
        // Wait two seconds.
        //
        Delay(2);
    
        //
        // Indicate that the decreasing interrupt priority test is beginning.
        //
        UARTprintf("\nDecreasing Priority\n");
    
        //
        // Set the interrupt priorities so that they are decreasing (i.e. C > B >
        // A).
        //
        ROM_IntPrioritySet(INT_GPIOA, 0x80);
        ROM_IntPrioritySet(INT_GPIOB, 0x40);
        ROM_IntPrioritySet(INT_GPIOC, 0x00);
    
        //
        // Reset the interrupt flags.
        //
        g_ui32GPIOa = 0;
        g_ui32GPIOb = 0;
        g_ui32GPIOc = 0;
        g_ui32Index = 1;
    
        //
        // Trigger the interrupt for GPIO C.
        //
        HWREG(NVIC_SW_TRIG) = INT_GPIOC - 16;
    
        //
        // Put the current interrupt state on the UART.
        //
        DisplayIntStatus();
    
        //
        // Verify that the interrupts were processed in the correct order.
        //
        if((g_ui32GPIOa != 3) || (g_ui32GPIOb != 2) || (g_ui32GPIOc != 1))
        {
            ui32Error |= 2;
        }
    
        //
        // Wait two seconds.
        //
        Delay(2);
    
        //
        // Indicate that the increasing interrupt priority test is beginning.
        //
        UARTprintf("\nIncreasing Priority\n");
    
        //
        // Set the interrupt priorities so that they are increasing (i.e. C < B <
        // A).
        //
        ROM_IntPrioritySet(INT_GPIOA, 0x00);
        ROM_IntPrioritySet(INT_GPIOB, 0x40);
        ROM_IntPrioritySet(INT_GPIOC, 0x80);
    
        //
        // Reset the interrupt flags.
        //
        g_ui32GPIOa = 0;
        g_ui32GPIOb = 0;
        g_ui32GPIOc = 0;
        g_ui32Index = 1;
    
        //
        // Trigger the interrupt for GPIO C.
        //
        HWREG(NVIC_SW_TRIG) = INT_GPIOC - 16;
    
        //
        // Put the current interrupt state on the UART.
        //
        DisplayIntStatus();
    
        //
        // Verify that the interrupts were processed in the correct order.
        //
        if((g_ui32GPIOa != 1) || (g_ui32GPIOb != 2) || (g_ui32GPIOc != 3))
        {
            ui32Error |= 4;
        }
    
        //
        // Wait two seconds.
        //
        Delay(2);
    
        //
        // Disable the interrupts.
        //
        ROM_IntDisable(INT_GPIOA);
        ROM_IntDisable(INT_GPIOB);
        ROM_IntDisable(INT_GPIOC);
    
        //
        // Disable interrupts to the processor.
        //
        ROM_IntMasterDisable();
    
        //
        // Print out the test results.
        //
        UARTprintf("\nInterrupt Priority =: %s  >: %s  <: %s\n",
                   (ui32Error & 1) ? "Fail" : "Pass",
                   (ui32Error & 2) ? "Fail" : "Pass",
                   (ui32Error & 4) ? "Fail" : "Pass");
    
        //
        // Loop forever.
        //
        while(1)
        {
        }
    }
    

    So, this is a TIVAWARE example of interrupts priority, I want to use only two interrupts A and B. Check what happens with priority and without priority.

    So, forget about the square wave, I will toggle an LED in GPIO A interrupt with highest priority and I want to call an ADC interrupt every 10 seconds with secondary priority (P.S. How do i call ADC interrupt every 10 seconds, since Systick Timer has some limitations of 1sec)

    Now, when i changed this code to run forever, with only "increasing" priority, it still went to the second priority interrupt. Is it because the flag is updated in every interrupt fucntion? Also, should i use timers interrupts instead?

    So basically if i run two interrupts with prirorities: only the highest should run. But if I run with equal prirorities: LED should stop toggling every 10 sec ..when ADC starts sampling, and I would like to measure the time taken for the ADC sampling which will probably be some miliseconds and it should match the sampling frequency of the ADC.

    Thank you

    Regards,

    Kirthi R Kulkarni

  • Hello Kirthi

    I guess you are mistaken-ed about priority here. A higher priority means that when the the two interrupts occur together then which one will be taken up. Considering the device is operating in MHz range and the fact that these events are over in a matter of few 10s' of clock cycles, the visible effect will not be perceived.
  • Kirthi Kulkarni said:
    So, this is a TIVAWARE example of interrupts priority, I want to use only two interrupts A and B. Check what happens with priority and without priority.

    Kirthi Kulkarni said:
    So basically if i run two interrupts with prirorities: only the highest should run.

    Why would you think that? Have you actually tried the example?

    Kirthi Kulkarni said:
    But if I run with equal prirorities

    That is the same as no priorities

    Try writing some pseudo-code.  Don't worry about the I/O details. First we need to get your basic understanding of the concepts straight. Then we can worry about details.

    Robert