Software Interrupts (Timer Interrupts)
Introduction
GPTM (General-Purpose Timer Module)
The TM4C123GH6PM microcontroller includes programmable General-Purpose Timer Modules (GPTM) that support various timing and counting functions. The module offers both 16/32-bit and 32/64-bit "Wide" timers with different capabilities and resolutions.
Feature | 16/32-bit GPTM Blocks | 32/64-bit Wide GPTM Blocks |
---|---|---|
Timer Width | 16-bit timers (Timer A & B) or combined 32-bit timer | 32-bit timers (can combine as a 64-bit timer) |
Prescaler Resolution | 8-bit prescaler for 16-bit timers | 16-bit prescaler for 32-bit timers |
Both types of timers support a range of versatile features that enable precise timing and event counting:
Operating Modes
- One-Shot Mode: Timer runs once and stops automatically.
- Periodic Mode: Timer repeats continuously, restarting after each cycle.
- Other Modes: Various modes for specific applications, including capture and PWM you can explore in the datasheet.
Clock Source
The timer can be clocked either from the system clock or an external clock source. The TM4C123 microcontroller typically uses a 16 MHz external crystal oscillator as its main clock input. However, the system clock frequency is configurable through the internal PLL and clock dividers, allowing the MCU to run at different speeds. In Keil uVision projects for the TM4C123, the system clock is commonly configured to run at 50 MHz using the 16 MHz crystal and PLL settings.
Timer Configuration (Step-by-Step Explanation)
Configuring the timer on the TM4C123 microcontroller might look complicated at first, but it’s just a matter of following these steps carefully.
1. Enable the Clocks
Before using any peripheral like GPIO or a timer, the microcontroller needs to enable its clock signals. Think of this as turning on the power switch for those components.
SYSCTL->RCGCGPIO |= (1 << 5); // Enable clock for GPIO Port F (where LEDs are connected)
SYSCTL->RCGCTIMER |= (1 << 1); // Enable clock for Timer1 module
SYSCTL->RCGCGPIO
controls clocks to GPIO ports; bit 5 corresponds to Port F.SYSCTL->RCGCTIMER
controls clocks to timers; bit 1 corresponds to Timer1.
IMPORTANT
After enabling the clocks, it’s good to wait briefly to ensure the clocks are stable. We do this with a simple delay loop.
2. Configure the GPIO Pin for the LED
We want to blink the Blue LED, which is connected to PF2. So, we need to tell the microcontroller to set that pin as an output and enable its digital function.
GPIOF->DIR |= 0x04; // Set PF2 (Blue LED) as output
GPIOF->DEN |= 0x04; // Enable digital function for PF2
DIR
register configures pin direction:1
means output,0
means input.DEN
register enables digital functionality on the pin.
3. Disable the Timer Before Configuring
Before making any changes, we turn off the timer. This prevents any unwanted operation during setup.
TIMER1->CTL = 0; // Disable TIMER1A (bit 0 controls timer enable)
4. Set Timer Configuration
We must tell the timer how it should operate:
- The timer can be 16-bit or 32-bit. We choose 16-bit here.
- We select Periodic Mode, which means the timer counts down repeatedly and generates interrupts each cycle.
TIMER1->CFG = 0x4; // Configure Timer1 as 16-bit timer
TIMER1->TAMR = 0x2; // Set Timer1A to Periodic Timer mode
CFG = 0x4
means “16-bit timer configuration.”0x4
is for 16-bit timer mode.0x0
would be 32-bit timer mode.
TAMR = 0x2
means “Periodic mode.”0x1
would be One-Shot mode.0x2
is Periodic mode.0x3
is Capture mode.
5. Set the Prescaler and Reload Value
Timers count down from a starting value (reload value) at a frequency determined by the system clock and the prescaler.
- Prescaler: Divides the clock frequency further, making the timer count slower.
- Reload value (ILR): The value from which the timer counts down to zero.
With the system clock at 50 MHz:
TIMER1->TAPR = 256 - 1; // Prescaler value (255)
TIMER1->TAILR = 65536 - 1; // Reload value (65535)
The prescaler effectively extends the timer's range. It slows down how frequently the main timer counter decrements.
How does this affect timing?
Interrupt frequency =
So, the timer fires approximately 2.98 times per second, meaning every interrupt is about
For longer delays, we must use the 32-bit timer configuration, which allows us to set a larger reload value. But removes the prescaler option. In this case, the timing expression becomes:
For example, if we want a 1-second delay, we can set the reload value to 50,000,000 (for a 50 MHz clock), remove the prescaler, and set the timer to 32-bit mode.
TIMER1->CFG = 0x0; // Configure Timer1 as 32-bit timer
TIMER1->TAMR = 0x2; // Set Timer1A to Periodic Timer mode
TIMER1->TAILR = 50000000 - 1; // Reload value (50,000,000)
6. Clear Interrupt Flag and Enable Timer Interrupt
Before enabling interrupts, clear any existing interrupt flags to avoid immediate triggers.
TIMER1->ICR = 0x1; // Clear timeout interrupt flag
TIMER1->IMR |= 0x1; // Enable timeout interrupt
ICR
clears interrupts by writing 1 to the bit.IMR
enables interrupt masks; setting bit 0 allows the timeout interrupt.
7. Enable Timer and Interrupt in NVIC
Now, turn the timer on and enable the interrupt in the microcontroller’s interrupt controller.
TIMER1->CTL |= 0x1; // Enable Timer1A
NVIC->ISER[0] |= (1 << 21); // Enable interrupt number 21 (Timer1A) in NVIC
CTL |= 0x1
enables the timer.NVIC->ISER[0]
enables interrupts for Timer1A (IRQ number 21).
Summary
- The timer counts down from
TAILR
at a frequency divided by the prescaler. - When it reaches zero, it triggers an interrupt.
- Your interrupt handler will run and can toggle the LED or do any other action.
- The timer automatically reloads and repeats this cycle (because of periodic mode).
Timer Registers
Register Name | Description |
---|---|
CFG | Configures the timer mode (0x4 : 16-bit or 0x0 : 32-bit). |
TAMR | Timer A Mode Register, sets the timer mode (0x1 : One-Shot, 0x2 : Periodic). |
TAPR | Timer A Prescale Register, sets the prescaler value. |
TAILR | Timer A Interval Load Register, sets the reload value. |
ICR | Interrupt Clear Register, clears the interrupt flag. |
IMR | Interrupt Mask Register, enables/disables interrupts. (0x1 : Timeout) |
MIS | Masked Interrupt Status Register, shows which interrupts are active. |
CTL | Control register for enabling/disabling the timer. (0x1 : Enable, 0x0 : Disable) |
NVIC->ISER | Interrupt Set-Enable Register, enables specific interrupts in the NVIC. |
Example Code
Maximum 16-bit Timer Delay
#include "TM4C123.h"
#define RED 0x02
#define BLUE 0x04
#define GREEN 0x08
#define YELLOW RED + GREEN
#define MAGENTA BLUE + RED
#define CYAN GREEN + BLUE
#define WHITE RED + GREEN + BLUE
#define SW1 0x10
#define SW2 0x01
#define DELAY 900000
const int sequence[] = {RED, BLUE, GREEN, YELLOW, MAGENTA, CYAN, WHITE};
int index = 0;
void delay( volatile unsigned long ulLoop ){
for (ulLoop = 0; ulLoop < DELAY; ulLoop++) {
for (ulLoop = 0; ulLoop < DELAY; ulLoop++) {
}
}
}
int main(void)
{
SYSCTL->RCGCGPIO |= (1<<5);
SYSCTL->RCGCTIMER |= (1<<1);
delay(0);
GPIOF->DIR |= BLUE;
GPIOF->DEN |= BLUE;
TIMER1->CTL = 0; // Disable the timer
TIMER1->CFG = 0x4; // Choose 16-bit mode
TIMER1->TAMR = 0x02; // Periodic mode
TIMER1->TAPR = 256 - 1; // Prescaler
TIMER1->TAILR = 65536 - 1; // Initial Value
TIMER1->ICR = 0x1; // Clear Any Prior Interrupts
TIMER1->IMR |=(1<<0); // Enable Timeout Interrupt
TIMER1->CTL |= 0x01; // Enable the timer
NVIC->ISER[0] |= (1<<21);
while(1)
{
}
}
void TIMER1A_Handler()
{
if(TIMER1->MIS & 0x1)
GPIOF->DATA ^= BLUE;
TIMER1->ICR = 0x1;
}
Lab Work
- Modify the code above to make the GREEN LED blinks every 100ms.
- Modify the code above to make the RED LED blinks every 4s.
- Use the onboard LED and another two external LEDs with the TM4C123G board to make one LED flashes every 10 seconds, one flashes every 5 seconds, and one flashes every one second.