avr-libc-dev
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[avr-libc-dev] Re: C++ Interrupts


From: Ron Kreymborg
Subject: [avr-libc-dev] Re: C++ Interrupts
Date: Thu, 31 Jan 2008 17:42:01 +1100

> 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/




reply via email to

[Prev in Thread] Current Thread [Next in Thread]