How to define an interrupt service routine for MSP430 with LLVM/Clang+GCC?

1.1k views Asked by At

When compiling with GCC, an ISR is defined by marking it with an interrupt attribute with a vector number defined in msp430fr*.h header that ships with GCC toolchain distributed by TI:

__attribute__ ((interrupt(TIMER2_A1_VECTOR)))
void TIMER2_A1_ISR (void) { ... }

However, when compiling with LLVM/Clang and assembling and linking with GCC

clang -emit-llvm -c -MD --target=msp430 -D__MSP430FR5969__ -nobuiltininc -nostdinc++ -isysroot /none -O1 -g -std=c99 -pedantic -Wall -I /opt/ti/msp430-gcc/lib/gcc/msp430-elf/4.9.1/include -I /opt/ti/msp430-gcc/msp430-elf/include -I /opt/ti/msp430-gcc/include -I ../src  -DBOARD_MSP_TS430  ../../src/main.c -o main.bc

the above causes a compile-time error:

../../src/main.c:80:17: error: 'interrupt' attribute parameter 38 is out of bounds
__attribute__ ((interrupt(TIMER2_A1_VECTOR)))
            ^         ~~~~~~~~~~~~~~~~
1

There are 1 answers

0
alexei On

The error from clang is due to the hardcoded restriction on the interrupt vector number to be even and below 30 in handleMSP430InterruptAttr in tools/clang/lib/Sema/SemaDeclAttr.cpp.

But, even ignoring this, the linker script with GCC from TI is not compatible with Clang, because Clang, unlike GCC, does not generate sections for the vectors, it only generates symbols (aliases), like __isr_6 for interrupt(12). The linker script shipped in the TI GCC distribution operates on sections, like so:

 VECT38           : ORIGIN = 0xFFDA, LENGTH = 0x0002
 ...
 __interrupt_vector_38  : {
     KEEP (*(__interrupt_vector_38))
     KEEP (*(__interrupt_vector_timer2_a1))
 } > VECT38

We define a symbol for the vector and put it in its own section named as the linker script wants it. We still want the interrupt attribute, because it marks the ISR function with the right calling convention, etc. The number can be dummy, 0, re-using is ok, Clang suffixes the aliases it generates. (In this solution, the 2 bytes per alias symbol defined by Clang are wasted.)

#ifdef __clang__
__attribute__ ((interrupt(0)))
#else
__attribute__ ((interrupt(TIMER2_A1_VECTOR)))
#endif
void TIMER2_A1_ISR (void)
{  ... }  
#ifdef __clang__
__attribute__ ((section("__interrupt_vector_timer2_a1"),aligned(2)))
void (*__vector_timer2_a1)(void) = TIMER2_A1_ISR;
#endif