ruduino
ruduino copied to clipboard
Interrupt handler symbol name incorrect?
The README shows
pub unsafe extern "avr-interrupt" fn _ivr_timer1_compare_a() {
as interrupt handler for timer1 but that didn't work for me on the Arduino Uno Rev3.
Every time the interrupt arrived, the board did a full reset because no interrupt handler was correctly defined.
This worked:
pub unsafe extern "C" fn __vector_11() {
as that is what ISR(TIMER1_COMPA_vect) (see e.g. here) expands to when used from the Arduino IDE.
I just learned it should be
pub unsafe extern "avr-interrupt" fn __vector_11() {
instead of
pub unsafe extern "C" fn __vector_11() {
because otherwise the ISR can be called only once.
I suspect that is about
Patching into the vector table is only one part of the problem. The compiler uses, by convention, a set of registers when it's normally executing compiler-generated code. It's important that these registers, as well as the status register, get saved and restored. The extra code needed to do this is enabled by tagging the interrupt function with
__attribute__((signal)).
from http://www.nongnu.org/avr-libc/user-manual/group__avr__interrupts.html
In particular TIFR1 becomes 6 with extern "C" and 4 with extern "avr-interrupt".
By the way, I implemented Arduino's micros() logic and counter/interrupt approach in Rust for a project here, in case anybody is interested:
https://github.com/nh2/quadcopter-simulation/blob/8a3652b8a704877156e91c0691ce8ce37588eb53/arduino-accel-rust/src/main.rs#L216
Would be nice to move much of that into ruduino later.
I wonder if the interrupt vector symbol name depends on the assembly code chosen for the IVT table.
For example, here's the objdump output of a hello world executable compiled with avr-gcc with an -mmcu specified. This will correspond to some assembly code (probably in the device-specific CRT) that will jump to interrupt functions like jmp __vector_11. I don't think we have an interrupt table included by default in avr-rust executables - there isn't any CRT loading done in Rust.
00000000 <__vectors>:
0: 0c 94 34 00 jmp 0x68 ; 0x68 <__ctors_end>
4: 0c 94 3e 00 jmp 0x7c ; 0x7c <__bad_interrupt>
8: 0c 94 3e 00 jmp 0x7c ; 0x7c <__bad_interrupt>
c: 0c 94 3e 00 jmp 0x7c ; 0x7c <__bad_interrupt>
10: 0c 94 3e 00 jmp 0x7c ; 0x7c <__bad_interrupt>
14: 0c 94 3e 00 jmp 0x7c ; 0x7c <__bad_interrupt>
18: 0c 94 3e 00 jmp 0x7c ; 0x7c <__bad_interrupt>
1c: 0c 94 3e 00 jmp 0x7c ; 0x7c <__bad_interrupt>
20: 0c 94 3e 00 jmp 0x7c ; 0x7c <__bad_interrupt>
24: 0c 94 3e 00 jmp 0x7c ; 0x7c <__bad_interrupt>
28: 0c 94 3e 00 jmp 0x7c ; 0x7c <__bad_interrupt>
2c: 0c 94 3e 00 jmp 0x7c ; 0x7c <__bad_interrupt>
30: 0c 94 3e 00 jmp 0x7c ; 0x7c <__bad_interrupt>
34: 0c 94 3e 00 jmp 0x7c ; 0x7c <__bad_interrupt>
38: 0c 94 3e 00 jmp 0x7c ; 0x7c <__bad_interrupt>
3c: 0c 94 3e 00 jmp 0x7c ; 0x7c <__bad_interrupt>
40: 0c 94 3e 00 jmp 0x7c ; 0x7c <__bad_interrupt>
44: 0c 94 3e 00 jmp 0x7c ; 0x7c <__bad_interrupt>
48: 0c 94 3e 00 jmp 0x7c ; 0x7c <__bad_interrupt>
4c: 0c 94 3e 00 jmp 0x7c ; 0x7c <__bad_interrupt>
50: 0c 94 3e 00 jmp 0x7c ; 0x7c <__bad_interrupt>
54: 0c 94 3e 00 jmp 0x7c ; 0x7c <__bad_interrupt>
58: 0c 94 3e 00 jmp 0x7c ; 0x7c <__bad_interrupt>
5c: 0c 94 3e 00 jmp 0x7c ; 0x7c <__bad_interrupt>
60: 0c 94 3e 00 jmp 0x7c ; 0x7c <__bad_interrupt>
64: 0c 94 3e 00 jmp 0x7c ; 0x7c <__bad_interrupt>
Perhaps the README is using a different IVT jump table with different interrupt function symbol names?
It raises a good question - how to go about standardising it
if the interrupt vector symbol name depends on the assembly code chosen for the IVT table.
Yes, it certainly does. The one shown comes from my custom assembly, which has the aim of not linking to any avr-gcc code whatsoever. This means I get to pick more expressive names.
Raised #12 for coming up with a single, ecosystem-wide way to define interrupts.
Does the function actually need to be declared unsafe?