Atmel AT32UC3
Home - Developer - Contact us

 

Up

Introduction

Literature

Chapter 1: Start

Chapter 2: Clocks

Chapter 3: Port

Chapter 4: Interrupt

Chapter 5: Timer

Chapter 6: Real Time

Chapter 7: Serial Link

 

Lecture Material

Application_4
Application_4a
Application_4b

Chapter 4

In the last chapter we used polling to check the state of the switches on the STK600 board. For simple programs and for time-critical applications polling can be the best solution. Otherwise handling events by interrupts is the most appropriate method. The AT32UC3A3 family of processors has a very elaborate interrupt structure, with which one can handle internal and external events very efficiently. We will extend the 'running LEDs' program 'Application_3a' and introduce interrupts for handling push-button events as an example.

Interrupts


Interrupt Controller (from AT32UC3A3 datasheet).

The AT32UC3A3 set of processors has an extensive number of request lines: there are 64 groups of requests and each request group has 32 request lines connected to peripheral devices. For each interrupt group there is an :

In addition there are 4 Interrupt Cause Registers, one for each priority, in which the group is shown with a currently active interrupt of that priority.

If an interrupt occurs, the procesor checks if a higher priority interrupt is active. If not it will execute the interrupt routine which belongs to this interrupt group: its address is programmed as 14bit interrupt vector in the Interrupt Priority Register. In the interrupt routine the active interrupt has to be determined form the Interrupt Request Register of that interrupt group. Then any peripheral-device specific action has to be performed, such as determining why the device issued an interrupt request and if it has to be reset explicitely. Then the service of the interrupt starts. After finishing the service the processor leaves the interrupt service routine and continues normal operation. Things can become quite complicated if interrupt service routines themselves are interruptable by higher priority interrupts. A clear structure and a good documentation are essential to prevent difficult debugging sessions.

Not all lines of the Interrupt Controllerare used; on page 104/105 the lines are listed, which are connected to peripheral devices. Each 32bit GPIO port is connected to 4 interrupt lines of group 2 of the Interrupt Controller (see p.104 in the AT32UC3A3 datasheet); this means that the first group of 8bit of the GPIO-0 is connected to interrupt line 64, the second 8bits to line 72, the third 8bits to line 80 and the fourth 8bits to line 88 (Interrupt Controller Group 2).

Thus 8 I/O-lines of one GPIO port share one interrupt line of the interrupt controller. These 8 I/O-interrupt lines can individually be enabled or disabled in the Interrupt Enable Register. An interrupt can be generated by any level-change at one of the I/O-pins or at the rising edge or falling edge of a level-change. The Interrupt Mode Register 0/1 allows to set the interruopt condition. Since a number of interrupt lines come together to one interrupt, it is necessary to look up the interrupt source in the Interrupt Flag Register. This register allows also to clear active interrupts.

The general sequency for programming interrupts of GPIO ports is:

Programs

Application_4 is nearly identical to Application_3a apart from that the buttons cause an interrupt which is decoded and results in a service for start/stop, direction or delay. Therefore the routines for testing and reading the button state are no longer needed. To make things simple, the interrupt is serviced in a 'user'-file. The interrupt-related initialization routines as well as the LED-loop are also located in this file. Lateron we will separate the user execution and device dependent files.

The interrupt system is initialized in 'init.c' by a call to 'INTC_init_interrupts'. Then the interrupt service routine 'startstop_int_handler' is registered to the interrupt system by:


	INTC_register_interrupt(&startstop_int_handler, (AVR32_GPIO_IRQ_0+(STK_SPEED_0_BUTTON/8)), AVR32_INTC_INT0);
	

The interrupt service routine is preceded by a GNU-compiler macro __attribute__((__interrupt__)). In the service routine the GPIO Interrupt Flag Register is read and if flags are set, the requited action, like readjusting the speed, is taken.


Directory structure of Application 4.
	
__attribute__((__interrupt__))
static void button_int_handler() {
    int status;
    status = gpio_port->ifr;
    if ((status & (1 << STK_SPEED_0_BUTTON)) != 0) {	// speed 0
        delay = SPEED_0;
        gpio_port->ifrc = (1 << STK_SPEED_0_BUTTON);
    }
    ...
    if ((status & (1 << STK_STOP_BUTTON)) != 0) {		// stop
        run = false;
        gpio_port->ifrc = (1 << STK_STOP_BUTTON);
    }
}
	

Initiallization of the GPIO interrupts:


// enable interrupt for all buttons
gpio_port->iers = STK_PC_MASK;
// falling edge interrupt mode
gpio_port->imr0c = STK_PC_MASK;
gpio_port->imr1s = STK_PC_MASK;
	

To run 'Application_4', create a new project named 'Application_4', extract the zip-file from the Chapter Materials part and create a folder 'support' as described before and copy the files into the appropriate directories like shown in the overview. The user files should be located in the 'src' directory.

Application_4a cleans the user-application part and the interrupt service routine. The button action is initiated in the interrupt service routine, but is executed in the 'do_LEDs' called from the main loop in main.c since it is low priority. An interrupt created by the stop/run button sets the boolean run variable to false (stop) or true (run). The state of the variable is checked in the main loop. If it is true, the 'do_LEDs' routine in user.c is executed. Other variables, e.g. for the direction or speed, are set in the interrupt service routine and are executed in 'do_LEDs'.

Each time the 'do_LEDs' routine is started from the main loop, the counter addressing the LED is incremented or decremented by one. After the delay-loop control is returned to the loop in main.c.

The main program:


// main program 'main.c'
#include 
#include "user.h"

int main (void) {
  board_init();
  cpu_irq_enable();
  while (true) {
    if (ledrun) {
      do_LEDs();
    }
  }
}
	

The interrupt service routine deligates action via varaibles:


__attribute__((__interrupt__))
static void startstop_int_handler() {
    int status;
    status = gpio_port->ifr;
    if ((status & (1 << STK_SPEED_0_BUTTON)) != 0) {	// speed 0
        delay = SPEED_0;
        gpio_port->ifrc = (1 << STK_SPEED_0_BUTTON);
    }
    ...
    if ((status & (1 << STK_START_BUTTON)) != 0) {		// start
        ledrun = true;
        gpio_port->ifrc = (1 << STK_START_BUTTON);
    }
    if ((status & (1 << STK_STOP_BUTTON)) != 0) {		// stop
        ledrun = false;
        gpio_port->ifrc = (1 << STK_STOP_BUTTON);
    }
}
	

Only some characteristic lines of code are listed. For a complete listing see 'Application_4a' in the Chapter Material. To run 'Application_4a', create a new project named 'Application_4a', extract the zip-file from the Chapter Materials part and create a folder 'support' as described before and copy the files into the appropriate directories (the directory structure is the same as in'Appliucation_4'. The user files should be located in the 'src' directory.

Application_4b demonstrates the use of ASF GPIO-handling. It replaces the direct writing to the LED-ports, reading from the button-ports and the initialization with calls to the GPIO-handler routines. This has the advantage of abstraction from the hardware, but has the disadvantage of lots of overhead because of the abstraction. Nevertheless, if one likes to keep one's distance from specific hardware, this is the way to go. If one is somewhat fimilar with the hardware, direct accessing the hardware has quite a speed advantage and - if written carefully - helps to understand the properties and limitations of the hardware.

In order to add the gpio-handler, open the ASF-Wizard and add GPIO-handling to the project. In the directory 'src/AFS/avr32/driver' a subdirectory 'gpio' with files gpio.c and gpio.h will appear. We rewrite the direct access to registers with calls to gpio.c. For a complete listing see the file user.c in the Chapter Materials section.

The interrupt service routine:


__attribute__((__interrupt__))
static void startstop_int_handler() {
    if (gpio_get_pin_interrupt_flag(STK_SPEED_0_BUTTON)) {    // speed 0
        delay = SPEED_0;
        gpio_clear_pin_interrupt_flag(STK_SPEED_0_BUTTON);
    }
	...
	

The LED-run routine:


void do_LEDs() {
    long count;
    switch (lcount) {
        case 0:
            if (direction == 1) {
                gpio_set_pin_high(LED7_GPIO);
            } else {
                gpio_set_pin_high(LED1_GPIO);
            }
            gpio_set_pin_low(LED0_GPIO);
            break;
        ...
	

The initialization:


void initialize_STK_PUSH_BUTTON() {
    // set buttons gpio input
    gpio_configure_group(GPIO_PUSH_BUTTON_PORT, GPIO_PUSH_BUTTON_MASK, GPIO_DIR_INPUT);
    // register interrupt service routine
    INTC_register_interrupt(&startstop_int_handler, (AVR32_GPIO_IRQ_0+(STK_SPEED_0_BUTTON/8)), AVR32_INTC_INT0);
    // enable button interrupts and interrupt mode to falling edge
    gpio_enable_pin_interrupt(STK_SPEED_0_BUTTON, GPIO_FALLING_EDGE);
    gpio_enable_pin_interrupt(STK_SPEED_1_BUTTON, GPIO_FALLING_EDGE);
    gpio_enable_pin_interrupt(STK_SPEED_2_BUTTON, GPIO_FALLING_EDGE);
    gpio_enable_pin_interrupt(STK_SPEED_3_BUTTON, GPIO_FALLING_EDGE);
    gpio_enable_pin_interrupt(STK_DIR_UP_BUTTON, GPIO_FALLING_EDGE);
    gpio_enable_pin_interrupt(STK_DIR_DOWN_BUTTON, GPIO_FALLING_EDGE);
    gpio_enable_pin_interrupt(STK_STOP_BUTTON, GPIO_FALLING_EDGE);
    gpio_enable_pin_interrupt(STK_START_BUTTON, GPIO_FALLING_EDGE);
}

void initialize_STK_LED() {
    // set LEDs gpio output and outputs high
    gpio_configure_group(LED_PORT, LED_PORT_MASK, GPIO_DIR_OUTPUT | GPIO_INIT_HIGH);
}
	

Which of the methods (ASF or direct register access) is the best, is a personal question - and a question of space and speed. If there is enough space and no speed restrictions, using ASF is easier, but also less transparent.

info@tsseshop.com