Skip to content

Instantly share code, notes, and snippets.

@sabicalija
Last active February 2, 2023 05:47
Show Gist options
  • Save sabicalija/c38bd08cf87b30e465a5d007b0bfbe5f to your computer and use it in GitHub Desktop.
Save sabicalija/c38bd08cf87b30e465a5d007b0bfbe5f to your computer and use it in GitHub Desktop.
TM4C1294NCPDT Interrupts

Exercises

Practice makes perfect!

Exercise 01: Register ISR for GPIO IRQs (static)

Use the provided template and register an Interrupt Service Routine (ISR), statically, which toggles the LEDs on the board. Register the ISR with the tm4c startup file (tm4c1294ncpdt_startup_c) for a GPIO Interrupt Request (IRQ) to the port connected to the user switches. TIPS: Don't forget to use keywords such as extern and interrupt, which are possibly not written in the startup code.

Exercise 02: Register ISR for GPIO IRQs (dynamic)

Use the provided template and register an Interrupt Service Routine (ISR), dynamically during runtime, which toggles the LEDs on the board. Register the ISR with the functions provided by TivaWare for a GPIO Interrupt Request (IRQ) on the pin of the GPIO port connected to the user switches. TIPS: Don't forget to use keywords such as extern and interrupt, which are possibly not written in the startup code.

Exercise 03: Debounce

Registering ISRs for button events is accompanied by an unfortune behavior. Sometimes when you press the button, the LEDs appear to not toggle at all. This happens because the switches on our board bounce when we press them, causing the ISR to be run several times. To avoid this, we have to "debounce", that is, ensure that only one digital signal can be registered within a given time until the bouncing stops.

Implement an algorithm to ensure, that the application registers only one signal in a given time. Here is possible outline of an algorithm, but you are encouraged to realize your own ideas.

  1. Register an ISR for IRQ (falling-edge, PORTJ) to toggle the LEDs on the board.
  2. In the ISR
    1. Disable the IRQ
    2. Update the value of a global variable to indicate that a button was pressed
    3. Toggle the LEDs
  3. In the main thread (while loop)
    1. Test if button was pressed and act only upon this event
    2. Test if button is not pressed and decrease counter
    3. Test if button is pressed (in the meantime) to reset the counter
    4. Test if the counter has expired to clear the current and enable future interrupts, and release the global variable indicating the button status.
    5. Delay/Sleep for 1ms

Reseting the counter ensures that we only clear and enable the interrupt if the button release was "stable" on consecutive cycles.

HowTo: Interrupts on TivaC

When working with interrupts on the TivaC Launchpad, you will need additional C syntax and compiler features, that are typical to microcontroller applications. Some of the details are not defined by the C standard. Thus implementation may vary with different compilers. Check what compiler you are using to build you applications and read the documentation of the following features.

Compiler Manuals

Features

  • volatile: disable optimization of the compiler for a variable which might be modified by something external to the "obvious" control flow.
  • interrupt: uses special register-saving rules and a special return sequence and an implementation which stresses safety.
  • extern: declare a identifier (variable, function) defined in another (external) module (file).
  • #pragma: used to enable, disable, or access special compiler features.
  • static: used for variables/functions whose
    • scope is confined (private) to a function or a program, and
    • value is not discarded when the function or program exits

Tips

  • Disable interrupt processing on the processor before configuring new IRQs and registering ISRs to avoid interrupts during configuration and registration.
  • You cannot pass or return any values to the ISRs, but you can use global variables instead. Use the volatile qualifier for global variables accessed by the main thread and an ISR. However, use global variables only when required.
  • Keep the ISR short and handle long-running task in the main thread.

API

There are basically two approaches. You can either use

  • the microcontroller manual (TM4C1294NCPDT) and implement your application accessing the documented registers, or use
  • the peripheral driver manual (TivaWare) using the documented API.

When working at "register" level, there are severals files defining useful macros, for working with interrupts and the NVIC.

  • hw_ints.h: macros defining the interrupt assignment
  • hw_nvic.h: macros used when accessing NVIC hardware

Using the TivaWare "driver" API is outlined below. For further details on both approaches, please refer to the mentioned manuals.

TivaWare

TivaWare provides several function for working with interrupts on the TM4C1294NCPDT. First section shows functions related to the NVIC and global interrupt handling of the microcontroller. The later sections show some of the functions related to interrupt handling of interrupt-capable modules (e.g. GPIO, Timer).

NVIC

To be able to use the provided driver functions for the NVIC module in your program you have to include the associated library.

#include <driverlib/interrupt.h>

These function are used to activate and deactivate functionality of the NVIC and are used for both types of ISR registration, static and dynamic.

  • IntMasterEnable(): enables the processor interrupt.
  • IntMasterDisable(): disables the processor interrupt.
  • IntEnable(): enables an interrupt (NVIC module).
  • IntDisable(): disabled an interrupt (NVIC module).
  • IntIsEnabled(): checks if a peripheral interrupt is enabled.

The following function is used only in case of dynamic ISR registration during runtime.

  • IntRegister(): registers an ISR to be called when an the specified interrupt occurs.

GPIO

To be able to use the provided driver functions for the GPIO module in your program you have to include the associated library.

#include <driverlib/gpio.h>
  • GPIOIntTypeSet(): set the interrupt type for the specified pin(s) (e.g. falling/rising edge)
  • GPIOIntRegister(): registers an ISR for a GPIO port.
  • GPIOIntUnregister(): removes an ISR for a GPIO port.
  • GPIOIntEnable(): enables the specified GPIO interrupts (GPIO module).
  • GPIOIntDisable(): disables the specified GPIO interrupts (GPIO module).
  • GPIOIntClear(): clears the specified interrupt source.
  • GPIOIntStatus(): gets the interrupt status (active/deactive) for the specified GPIO port.

Registration of the ISRs is either done using file tm4c1294ncpdt_startup_ccs.c or by the GPIO driver function GPIOIntRegister(). The difference between IntRegister() and GPIOIntRegister() is, however, that the later one enables a given interrupt calling IntEnable() in addition. In case you register the function statically, you have to call the NVIC driver function IntEnable() to enable IRQ processing at the NVIC, otherwise, the IRQ will not be "passed" to the processor.

/*
* Event-driven LED toggling button interrupts.
*/
#include <stdint.h> /* C99 header for uint*_t types */
#include <stdbool.h> /* Driverlib headers require stdbool.h to be included first */
#include <driverlib/gpio.h> /* Supplies GPIO* functions and GPIO_PIN_x */
#include <driverlib/sysctl.h> /* Supplies SysCtl* functions and SYSCTL_* macros */
#include <driverlib/interrupt.h> /* Supplies Int* functions related to the NVIC */
#include <inc/hw_memmap.h> /* Supplies GPIO_PORTx_BASE */
#include <inc/hw_ints.h> /* Supplies INT_* */
#define F_CPU (16000000)
static void init_hardware(void) {
uint32_t ui32Strength;
uint32_t ui32PinType;
/* Activate GPIO ports */
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOJ);
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPION);
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
/* Set pin 0 of GPIO port J to digital input */
GPIOPinTypeGPIOInput(GPIO_PORTJ_BASE, GPIO_PIN_0);
/* Enable pull-up for button on pin 0 of port J */
GPIOPadConfigGet(GPIO_PORTJ_BASE, GPIO_PIN_0, &ui32Strength, &ui32PinType);
GPIOPadConfigSet(GPIO_PORTJ_BASE, GPIO_PIN_0, ui32Strength, GPIO_PIN_TYPE_STD_WPU);
/* Set output pins connected to LEDs */
GPIOPinTypeGPIOOutput(GPIO_PORTN_BASE, GPIO_PIN_1 | GPIO_PIN_0);
GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_4 | GPIO_PIN_0);
}
void toggle_led_isr(void)
{
// TODO: Clear the GPIO interrupt
// TODO: Toggle LEDs
}
int main(void)
{
/* Initialize hardware */
init_hardware();
/* TODO: Output initial state */
/* TODO: Interrupt configuration */
while (1) {
// Noop; Event-driven execution using ISRs
}
}
@Dvinothkanna
Copy link

Dear sir,
Kindly share the interrupt program file to understand more about..

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment