Search Microcontrollers

Tuesday, February 18, 2014

Stellaris Launchpad - Interrupts 1

The Cortex M4F has a powerful interrupt handling mechanism.
Since these kind of devices are normally used in applications where they control events happening around them, they need to have a flexible and efficient interrupt handling mechanism.

If you ever coded ISR (Interrupt Service Routines) for pretty much any platform, you probably know that is generally a bad idea to have two interrupts serviced at the same time.
When an interrupt is being serviced, a second interrupt is generally queued and waits for the first ISR to be completed.
While in many applications this could be ok -i.e. you click with your mouse and press a key on your keyboard almost simultaneously, but it is usually ok for the keyboard event to wait until the mouse event is handled or vice-versa-
When you are dealing with external sensors that might require a very quick response, this behavior may not be desirable or even acceptable.
What would be cool is to be able to set priorities to those interrupts and if the keyboard is more important of the mouse then we expect the mouse ISR routine to be interrupted by the keyboard one and resume right after the latter is completed.

The cortex M4F allows just that using a Nested Vector Interrupt Controller (NVIC) that handles via hardware all the needed complexity (Pushing a popping the machine states as needed and optimizing such processes for Interrupt concurrency).

These concepts are well explained in the great video by TI


To be honest I am not adding much with this post as everything is well explained in the video itself, however, for my (and eventually yours) future reference, I find it easier to write a summary of the concepts.

Now that you know how cool the interrupt handling is in the M4F, let's see how to use it in a basic setup.

By default all interrupt vector are redirected to a default vector function called IntDefaultHandler.
If you enable a timer interrupt, a uart interrupt etc, the interrupt vector function found in the MCU vector table (by default it starts at addr 0x0, leave it there unless you have a good reason not too) is called.

The Stellaris has 65 interrupts, each one has a service function address stored in the int vector table.
This means that if you want to use your interrupt service routine, you need to store its address in the before mentioned table.

Configuring your startup_ccs.c file

To achieve this you need to properly alter the file startup_ccs.c (you have a copy of it in each CCS project) file in two points :

1) Search for this data structure :

 #pragma DATA_SECTION(g_pfnVectors, ".intvecs")
void (* const g_pfnVectors[])(void) =

You will find an array of function pointers, on the right side comments are added to indicate which ISR each value represents.
Carefully browse those comments and locate the element related to the interrupt you need to handle.
Most likely the associated value will be IntDefaultHandler, if it is not either you already mdified the file or you are trying to manage something you probably should not (a reserved or "core" interrupt).
Replace IntDefaultHandler with the name of your ISR function (i.e. MyCoolISRFunction ) .


2) Now you updated the int vector table  to consider your ISR, however in the startup_ccs.c file such function is normally not defined (you defined it in your main.c or whatever other source file you are using).
To fix that, scroll on top of startup_ccs.c and locate a section that contains external declarations, it should be around line 20 or so.
There add your ISR as

extern void MyCoolISRFunction;    

where MyCoolISRFunction is the same name you used to define the ISR in main.c and you copied into the int vector table structure.

Steps needed to service a peripheral using an ISR 

1) Enable your peripheral XXXX with

 SysCtlPeripheralEnable(XXXX);

2) configure your peripheral as needed by setting gpio pind directions, timer, uart, spi... parameters

3) Enable the interrupt associated to your peripheral
IntEnable(XXXX);

4) Enable your peripheral to generate interrupts
i.e. TimerIntEnable(TIMER0_BASE,TIMER_TIMA_TIMEOUT);

5) Generally enable interrupts on the M4F
IntMasterEnable();

6) Fire up your peripheral if needed
i.e. TimerEnable(TIMER0_BASE,TIMER_A);

7) define your ISR function

void MyCoolISRFunction(void)
{
 // clear the peripheral interrupt i.e. :
 TimerIntClear(TIMER0_BASE,TIMER_TIMA_TIMEOUT);
/*
 do whatever you need to do
*/
}

Note that all steps from 1 to 7 happened in your main.c (or other source module you may have added) file.

8) Finally you need to update your startup_ccs.c file as explained in the "configure your startup_ccs.c file" section


1 comment:

HOLGER said...

Tanks for Info in IRQ.