Light Keyboard

This exercise aims at making clear the differences between two typical architectures for cyclic-executive-based embedded systems: round-robin and round-robin with interrupts. The basic idea is to associate leds and keys in such a way that a led is on when the corresponding key is pressed (for some time).

Architecture I: Round-Robin

This first version uses no interrupts. It simply polls the state of buttons in a tight loop, identifying those that are pressed and turning on the corresponding leds.

Pseudo code

1.
2.
3.
4.
void main(void) {
    while(1)
        leds_on(buttons_chk());
}

The buttons_chk function reads the data register from the I/O port to which the buttons are connected, returning a mask of pressed buttons, while leds_on takes the activation mask to set the corresponding bits of the data register from the I/O port to which the leds are connected.

Solutions

Architecture II: Round-Robin with Interrupts

To make things more interesting, we will now wait for a button to be pressed for at least 4 seconds before turning on the corresponding led. This is more easily achievable with another software architecture: round-robin with interrupts.

Interrupt Handling

First of all, you need to know how to handle external interrupts. Connect one of the STK500 buttons to one of the AVR's external interrupt pins and write a simple routine to handle that IRQ. You must configure this external interrupt in order that a button release (a rising edge on the interrupt pin) triggers an event (e.g. prints a bit pattern in the STK500's leds).

1.
2.
3.
4.
5.
6.
7.
8.
9.
void main(void) {
    int_handler(BUTTON, &button_handler);
    int_enable();
    while(1);
}

void button_handler(void) __ISR__ {
    leds_on(buttons_chk());
}

Timer Operation

After handling interrupts, you will need to get acquainted with basic timer operations. Set up a timer event in the AVR so that the leds print out a value after holding a button for 4 seconds.

Timer Frequency

A timer counts up a value every two clock cycles, and can be set-up to count from an arbitrary value (Time) up to it's maximum value (256 in an 8-bit timer). The timer can be configure to trigger an interrupt when it overflows or when its counter value matchs a defined value. The timer input clock can be prescaled by N from the System Clock, meaning that N system cycles correspond to one timer clock cycle. Thus, considering the timer is configured to issue interrupts on overflows, the formula for the interrupt frequency in an 8-bit timer is Clk/N*256.

Some tips:

Solutions