36 Interrupts-Asm
36 Interrupts-Asm
language
March 25, 2012
1 Introduction
2 Objective
#include <msp430.h>
#define LED_0 BIT0
__attribute__((interrupt(TIMERA1_VECTOR)))
timer_isr(void)
{
P1OUT ^= LED_0;
TACTL &= ~TAIFG;
}
void main(void)
{
P1OUT = 0;
P1DIR = LED_0;
1
while(1);
}
The above code congures Timer-A such that it generates an interrupt at a
rate of approximately twice per second. Each time the ISR (interrupt service
routine) is called, it toggles the LED on bit 0 of P1OUT (the RED LED on the
launchpad board); it also clears the interrupt ag (TAIFG) which is bit 0 of the
register TACTL.
3 Rewriting timer_isr
P1OUT ^= LED_0;
LED_0 is #dened to BIT0 and BIT0 expands to the constant 1. So, the above
statement is eectively:
P1OUT ^= 1;
One way to translate this is to move (using a byte move, mov.b) P1OUT (whose
memory mapped address is 0x21) to a register (say r15), use xor.b to toggle the
least signicant bit of the register and write the register's value back to P1OUT .
2
The next statement is:
TACTL &= ~1
The least signicant bit (D0'th bit) of TACTL is the interrupt ag bit, TAIFG
- the above statement clears that bit.
How do you implement this in assembly?
Let us look at the bit pattern for ~1:
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0
The constant -2, expressed in two's complement form, has the very same bit
3
pattern . So one method is to rst store the value of TACTL in a register (say
r15) using a word move
4 (mov.w), do a bitwise and with the constant -2 and
5
store back to TACTL . If you refer the device specic data sheet, you will nd
that the address of TACTL is 0x160.
2 Much better: directly do an xor.b to P1OUT. You will note that gcc, with optimizations
enabled, does it like this.
3 You represent -2 in two's complement form by rst writing 2 in binary form, taking ones
complement of all the bits and then adding one to it
4 TACTL is a 16 bit register while P1OUT is 8 bit
5 Or much better: directly do an and.w with TACTL
2
3.1 Saving and restoring registers
An ISR may get invoked any time during the execution of your program. Say
you are modifying a register r15 in your ISR; this will create trouble if the same
register is being used in some other part of your code. So it is always a good
idea to make sure that once the ISR returns, the registers which were modied
in the body of the ISR regain their old values. The easiest way to do this is to
push the registers which are going to be modied within the ISR to the stack
at the beginning of the ISR's body and then pop them out just before returning.
ret
3
4 Rewriting main
L1: jmp L1
is sucient.
How does the processor nd out the address of the instruction to be executed
when a timer overow interrupt is generated?
MSP430 processors use what is called a vectored interrupts scheme where
for each specic type of hardware interrupt, there is one location in memory
which should hold the address of the rst instruction of the ISR to be executed.
The set of locations which hold the addresses of Interrupt Service Routines is
called an IVT (interrupt vector table). On the MSP430g2231, the vector table is
from 0xe0 to 0x in ash memory. The address of the ISR to handle Timer-A
overow should be at 0xf0.
Let us say we have written the ISR code under the label timer_isr. The
following assembler directives, inserted at the end of the program, will set up
the vectors correctly:
4
org 0xfff0
dw timer_isr
This will result in mspdebug writing the address of the rst instruction under
the label timer_isr to ash memory location 0xf0.
Of course, we also need the following directives:
org 0xfffe
dw main
(assuming that we have a label main under which we have written the instruc-
tions for our main program).
Upon system reset, the processor will read the two byte value at location
0xfe (called the reset vector) and transfers control to that location in memory.
When a timer overow interrupt is generated, the processor reads the 2 bytes
at location 0xf0:0xf1, treats those two bytes as the address of the ISR and
transfers control to the ISR.
6 Exercises
2. Compile the original C program with the -S option and read the generated
assembly code. Compile the code once again with -S and -O3 options and
analyse the output.
7 Test