EmbeddedRelated.com
Forums
The 2024 Embedded Online Conference

AVR-gnuC interrupt handler question

Started by Fred Bartoli September 4, 2006
Hello,
I'm definitely not a C programmer so the answer is probably obvious, but 
anyway here is my question:

I've a small 4x2 keyboard that's handled through interrupts.
Each of the 2 columns is connected to an IT input (resp. INT0 & INT1)
I want to serve both interrupts through the same handler.

I'm using WinAVR and AVR-libc, so I have something like the following 
snippet:

#include <avr/interrupt.h>

ISR(INT0_vect)
{
...
}


But I don't understand how to force the compiler to make the INT1 vector 
point to the INT0 service routine.



-- 
Thanks,
Fred.
Fred Bartoli wrote:

> I'm definitely not a C programmer so the answer is probably obvious, but > anyway here is my question:
[...]
> But I don't understand how to force the compiler to make the INT1 vector > point to the INT0 service routine.
There's a bad way to do it, and several worse ways to do it. No elegant method exists, really. What I would suggest is to put a label inside the INT0 ISR and put a goto inside the INT1 ISR. Yuck, yuck, yuck. But check the disassembly. You MIGHT need to inline an assembly jump to that goto.
larwe a &#4294967295;crit :
> Fred Bartoli wrote: > >> I'm definitely not a C programmer so the answer is probably obvious, but >> anyway here is my question: > [...] >> But I don't understand how to force the compiler to make the INT1 vector >> point to the INT0 service routine. > > There's a bad way to do it, and several worse ways to do it. No elegant > method exists, really. > > What I would suggest is to put a label inside the INT0 ISR and put a > goto inside the INT1 ISR. Yuck, yuck, yuck. > > But check the disassembly. You MIGHT need to inline an assembly jump to > that goto. >
Thanks. I thought about this and also going the include way, which avoids duplicating the source code, but not the obj code. I expected there was a cleaner way. What about the worse ones ?-) -- Thanks, Fred.
Fred Bartoli wrote:

> > There's a bad way to do it, and several worse ways to do it. No elegant > > method exists, really. > > > I thought about this and also going the include way, which avoids > duplicating the source code, but not the obj code. > I expected there was a cleaner way.
How much of a masochist are you, really? :) The problem is that you are trying to have a single function have two names. There are no nice ways to do this.
On Mon, 04 Sep 2006 21:53:21 +0200, Fred Bartoli wrote:

> Hello, > I'm definitely not a C programmer so the answer is probably obvious, but > anyway here is my question: > > I've a small 4x2 keyboard that's handled through interrupts. > Each of the 2 columns is connected to an IT input (resp. INT0 & INT1) > I want to serve both interrupts through the same handler. > > I'm using WinAVR and AVR-libc, so I have something like the following > snippet: > > #include <avr/interrupt.h> > > ISR(INT0_vect) > { > ... > } > > > But I don't understand how to force the compiler to make the INT1 vector > point to the INT0 service routine.
Isn't it as simple as the following? Not quite the same, but achieves the same result. ISR(INT0_vect) { Common_Code(); } ISR(INT1_vect) { Common_Code(); } void Common_Code() { ... } ~Dave~
Dave a &#4294967295;crit :
> On Mon, 04 Sep 2006 21:53:21 +0200, Fred Bartoli wrote: > >> Hello, >> I'm definitely not a C programmer so the answer is probably obvious, but >> anyway here is my question: >> >> I've a small 4x2 keyboard that's handled through interrupts. >> Each of the 2 columns is connected to an IT input (resp. INT0 & INT1) >> I want to serve both interrupts through the same handler. >> >> I'm using WinAVR and AVR-libc, so I have something like the following >> snippet: >> >> #include <avr/interrupt.h> >> >> ISR(INT0_vect) >> { >> ... >> } >> >> >> But I don't understand how to force the compiler to make the INT1 vector >> point to the INT0 service routine. > > Isn't it as simple as the following? Not quite the same, but achieves the > same result. > > ISR(INT0_vect) > { > Common_Code(); > } > > ISR(INT1_vect) > { > Common_Code(); > } > > void Common_Code() > { > ... > } > > > > ~Dave~
Sure that'll work, but I'd like to avoid the huge additional push-pop overhead implied by the function call. It seems (avrfreaks) there's a solution through using aliasing either through an alias attribute to one of the interrupt routines (clean but not supported in the current winavr built) or through explicitly aliasing at the linking step. -- Thanks, Fred.
Fred Bartoli wrote:

> I've a small 4x2 keyboard that's handled through interrupts. > Each of the 2 columns is connected to an IT input (resp. INT0 & INT1) > I want to serve both interrupts through the same handler. > > I'm using WinAVR and AVR-libc, so I have something like the following > snippet: > > #include <avr/interrupt.h> > > ISR(INT0_vect) > { > ... > } > > > But I don't understand how to force the compiler to make the INT1 vector > point to the INT0 service routine.
You could use something like this: ISR(INT1_vect) __attribute__ ((alias("__vector_1"))); ISR(INT0_vect) { ... } The string "__vector_1" depends on the vector number of the INT0 interrupt. This is target dependent. I don't know how to avoid putting that literal name in the string. Regards, Arlet
Arlet a &#4294967295;crit :
> Fred Bartoli wrote: > >> I've a small 4x2 keyboard that's handled through interrupts. >> Each of the 2 columns is connected to an IT input (resp. INT0 & INT1) >> I want to serve both interrupts through the same handler. >> >> I'm using WinAVR and AVR-libc, so I have something like the following >> snippet: >> >> #include <avr/interrupt.h> >> >> ISR(INT0_vect) >> { >> ... >> } >> >> >> But I don't understand how to force the compiler to make the INT1 vector >> point to the INT0 service routine. > > You could use something like this: > > ISR(INT1_vect) __attribute__ ((alias("__vector_1"))); > > ISR(INT0_vect) > { > ... > } > > The string "__vector_1" depends on the vector number of the INT0 > interrupt. This is target dependent. I don't know how to avoid putting > that literal name in the string. > > Regards, > Arlet >
Unfortunately the alias attribute isn't supported in the current gcc version for winavr (gcc 3.4.6). Suggested on the avrfreaks forum is to alias the names at the link step (add -Wl,--defsym=__vector_2=__vector_1 ). Not ultra clean, but works nicely and is said to be supported on the next release, so I'll go for it. Thanks to all. -- Thanks, Fred.
Fred Bartoli wrote:
> Dave a &#4294967295;crit : >> On Mon, 04 Sep 2006 21:53:21 +0200, Fred Bartoli wrote: >> >>> Hello, >>> I'm definitely not a C programmer so the answer is probably obvious, >>> but anyway here is my question: >>> >>> I've a small 4x2 keyboard that's handled through interrupts. >>> Each of the 2 columns is connected to an IT input (resp. INT0 & INT1) >>> I want to serve both interrupts through the same handler. >>> >>> I'm using WinAVR and AVR-libc, so I have something like the following >>> snippet: >>> >>> #include <avr/interrupt.h> >>> >>> ISR(INT0_vect) >>> { >>> ... >>> } >>> >>> >>> But I don't understand how to force the compiler to make the INT1 >>> vector point to the INT0 service routine. >> >> Isn't it as simple as the following? Not quite the same, but achieves >> the >> same result. >> >> ISR(INT0_vect) >> { >> Common_Code(); >> } >> >> ISR(INT1_vect) >> { >> Common_Code(); >> } >> >> void Common_Code() >> { >> ... >> } >> >> >> >> ~Dave~ > > Sure that'll work, but I'd like to avoid the huge additional push-pop > overhead implied by the function call. >
If you structure your code carefully (i.e., make Common_Code() static inline, and defined before the interrupt routines), then there will be no extra push-pop overhead. You'll get the code generated twice, but unless you are using the tiniest of devices (or a huge "Common_Code"), there is no practical problem.
> It seems (avrfreaks) there's a solution through using aliasing either > through an alias attribute to one of the interrupt routines (clean but > not supported in the current winavr built) or through explicitly > aliasing at the linking step. >
Both these will work. You could also make the second interrupt routine a pure assembly function which jumps directly to the first routine.

The 2024 Embedded Online Conference