> IMHO the only way is to define the interrupt method in the class with > interrupt attributes and then alias the mangled name to the AVR vector > so the compiler can find it during global name reconciliation. This > would be very neat and simple if we could develop a simple name > mangling macro. > > Ron
With advise from Daniel Lohmann, Andrew Haley and Brian Dessent over on the gcc-help list ("Mangle functions"), using the gcc "asm" keyword considerably simplifies defining interrupt methods in C++ classes. The asm keyword as it applies to function names is described in 5.37 of the gcc manual, and essentially specifies the equivalent assembler name for the target function name. Its use allows the user to use his or her own names for class interrupt methods. For avr-gcc it requires two new macros: #define STRINGIFY(name) #name #define CLASS_IRQ(name, vector) \ static void name(void) asm(STRINGIFY(vector)) \ __attribute__ ((signal, __INTR_ATTRS)) Using the simple example of previous posts on this topic, the interrupt class header for a '128 TIMER0 overflow looks like: class CTimer0Interrupt { public: CTimer0Interrupt(); ~CTimer0Interrupt(); private: CLASS_IRQ(OverflowInterrupt, TIMER0_OVF_vect); }; The macro declares the interrupt handler as static because providing a non-static signal function with a this pointer seems rather hit and miss for gcc. Mandating a static declaration ensures the programmer is not tempted to manipulate any local data. Of course there should never be any local data. The cpp implementation file looks like: //*************************************************************** // Timer0Interrupt.cpp // #include "Timer0.h" #include "Timer0Interrupt.h" extern CTimer0 Timer0; //--------------------------------------------------------------- CTimer0Interrupt::CTimer0Interrupt() { TCNT0 = TIMER0_TIMEOUT; TCCR0 = 0x04; TIMSK |= (1<<TOIE0); // enable overflow interrupts } //--------------------------------------------------------------- CTimer0Interrupt::~CTimer0Interrupt() { TIMSK &= ~(1<<TOIE0); // disable Timer0 timeout interrupt } //--------------------------------------------------------------- void CTimer0Interrupt::OverflowInterrupt(void) { TCNT0 = TIMER0_TIMEOUT; // restart the timeout Timer0.SetOverflowFlag(); // tell our friend of the event } Note that the interrupt handler is declared just like any other method. All processing associated with the interrupt is performed in the class associated with, and responsible for, controlling the peripheral. In this case the CTimer0 class of which the CTimer0Interrupt class is both class data and a friend: class CTimer0 { friend class CTimer0Interrupt; public: CTimer0(); ~CTimer0(); int GetTimer0Flags(void); private: void SetOverflowFlag(void); private: volatile int mTimer0Flags; CTimer0Interrupt mTimer0Interrupt; }; Where speed is of the essence, the interrupt class can directly modify the owning peripheral class data. A simple example is: void CTimer0Interrupt::OverflowInterrupt(void) { TCNT0 = TIMER0_TIMEOUT; // restart the timeout Timer0.mTimer0Flags |= TIMER0_OVERFLOW; } To me this seems a good solution for handling interrupts in avr-gcc C++ projects by integrating the handlers into the peripheral class and keeping with the spirit of C++. Ron E-mail message checked by Spyware Doctor (5.5.0.178) Database version: 5.09100 http://www.pctools.com/spyware-doctor/ _______________________________________________ AVR-libc-dev mailing list AVR-libc-dev@nongnu.org http://lists.nongnu.org/mailman/listinfo/avr-libc-dev