[CODE] [C] Better GCC Interrupt Macro

Go To Last Post
17 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

NOTE: This article is now obsolete, as the API has been incorporated into the newer versions of avr-libc.

Updated 19/11/06 for new ISR_ALIAS attribute and backwards compatibility
Updated 17/05/07 to fix ISR_ALIASOF definition

Freaks,

Most of you who use GCC are familiar with the method in which interrupt routines (ISRs) are defined and used. Before the latest AVRLibC major update, there existed two ways to declare an interrupt service routine:

SIGNAL(VectorName)
{
// Code goes here
}

And:

INTERRUPT(VectorName)
{
// Code goes here
}

While the two methods were easy to differentiate to the seasoned GCC user, these two macro names were a constant source of confusion to those new to the C language - or even just those new to GCC. The difference between the two was subtle, but important.

SIGNAL. This declares an ISR which keeps the global interrupt enable flag inside SREG disabled. It is by far the most commonly needed type of ISR, and sadly the least used by newbies.

INTERRUPT. Exactly the same as SIGNAL, except interrupts are re-enabled at the very start of the ISR code. Most newbies who did not study the AVRLibC manual properly chose this macro because of it's obvious name.

Knowing that this was a great source of confusion - mainly due to the large amount of problems posted in the GCC section of this site - the developers of AVRLibC deprecated both macros and replaced it with a single new one, functionally equivalent to the old SIGNAL macro:

ISR(VectorName)
{
// Code goes here
}

Note: If you are going to use ISR(VectName) macro it may be worth to update to avr-libc version 1.4.4 due to some bugfixes concerning ISR() incompatibility with gcc 3.4.5.

This new name is more descriptive, and helped significantly. But the problem is now the opposite; newbies don't make mistakes, but seasoned GCC users no longer have an easy way to declare an ISR with the "interrupt" attribute. It's possible to create your own:

#define INT_ISR(vector)  \
void vector (void) __attribute__((interrupt)); \
void vector (void)

But this solution seems rather hacked-together. It's harder to determine what the difference is between the INT_ISR and plain old ISR. I present my solution to the problem, a header file I made called "ISRMacro.h":

ISRMacro.h

/* Must be included after avr/interrupt.h. This file re-defines the new
   ISR macro to extend it to allow custom attributes. When the old ISR
   macros SIGNAL and INTERRUPT were depricated, no suitable replacement
   was specifed for interruptable ISR routine (and no macro at all exists
   for naked ISRs). This file avoids the clumsyness of declaring the ISR
   routines manually with custom attributes and thus gives code uniformity.

   As a bonus, the default vector (called when an interrupt fires which does
   not have an associated ISR routine) is aliased here to a more descriptive
   name - use the new name as you would a standard signal name.
   
   The new macro is backwards compatible with the original ISR macro.
   
   The avaliable attributes are:
      1) ISR_BLOCK         - ISR, interrupts disable until ISR completes.
      2) ISR_NOBLOCK       - ISR, interrupts enabled until ISR completes.
      3) ISR_NAKED         - ISR, no prologue or epilogue.
      4) ISR_ALIASOF(vect) - ISR, alias to another interrupt vector's ISR. GCC 4.2+ only.

   For GCC 3.x vector aliases, you can use the ISR_ALIAS_COMPAT macro (instead
   of ISR macro). Works with GCC 3.x as well as GCC 4.x, but compat aliased vector
   ISR will contain a JMP instruction that the non-compat aliased vector does not have.
*/

#ifndef ISRMACRO_H
#define ISRMACRO_H

   // If present, kill the current ISR macro:
   #if defined(ISR)
      #undef ISR
   #endif
   
   // The default vector is given a more descriptive alias here:
   #define BADISR_vect __vector_default
   
   // Return from interrupt command, defined for convenience in ISR_NAKED routines:
   #define reti() asm volatile ("RETI"::)
   
   // Internal macros:
   #define __replace_and_string(name) #name
   
   // Definition of the attributes here, GCC version specific:
   #if defined(__GNUC__) && (__GNUC__ > 3)
      #define ISR_NOBLOCK    __attribute__((interrupt, used, externally_visible))
      #define ISR_BLOCK      __attribute__((signal, used, externally_visible))
      #define ISR_NAKED      __attribute__((signal, naked, used, externally_visible))
      #define ISR_ALIASOF(v) __attribute__((alias(__replace_and_string(v)))) // GCC 4.2 and greater only!
   #else
      #define ISR_NOBLOCK   __attribute__((interrupt))
      #define ISR_BLOCK     __attribute__((signal))
      #define ISR_NAKED     __attribute__((signal, naked))
   #endif

   // GCC 3.x compatible alias macro. Works with GCC 4.1 also:
   #define ISR_ALIAS_COMPAT(vector, aliasof)      \
      void vector (void) ISR_NAKED;               \
      void vector (void) { asm volatile ("jmp " __replace_and_string(aliasof) ::); }

   // New ISR macro definition:
   #define ISR(vector, ...)                       \
      void vector (void) ISR_BLOCK __VA_ARGS__;   \
      void vector (void)
#endif

Instead of creating extra macros, this header file alters the existing one. The new format is:

ISR(VectorName, Attribute)
{
// Code goes here
}

This leads to nicer-looking and more uniform ISR macros. If you want to create an ISR which blocks other ISRs from running until it has completed (signal attribute), you can use:

ISR(VectorName, ISR_BLOCK)
{
// Code goes here
}

Or, conversely, an ISR which itself be interrupted can be specified by:

ISR(VectorName, ISR_NOBLOCK)
{
// Code goes here
}

A third attribute (admittedly not commonly used) is ISR_NAKED, which creates an ISR which has no prologue or epilogue code. I've added it for completeness. Because the ISR_NAKED attribute also specifies that the routine is a signal (despite not having any prologue or epilogue code) the GCC extension to spell-check ISR vector names is still functional.

The final attribute (added 19/11/06) is in preparation for GCC4.2. It allows for the aliasing of one vector to another. An example of aliasing the PCINT0_vect vector to the PCINT1_vect vector:

ISR(PCINT0_vect, ISR_ALIASOF(PCINT1_vect));

If you are not using GCC 4.2 or greater, you can instead use the compatibility alias macro, which will work in all GCC versions, at the cost of a JMP instruction for the aliased vector:

ISR_ALIAS_COMPAT(PCINT0_vect, PCINT1_vect);

Finally, when debugging it can be desirable to create an ISR which runs if any vector without an accompanying ISR fires. This is usually done using the "__vector_default" signal name:

ISR(__vector_default)
{
// Bad interrupt code goes here
}

However the name is clumsy and undescriptive at best. The ISRMacro.h gives an alternate and more descriptive name to this vector, that of BADISR_vect (conforms with the latest ISR naming scheme). With the new name, you can specify a bad-ISR catching ISR which blocks other ISRs from running until it completes via:

ISR(BADISR_vect, ISR_BLOCK)
{
// Bad interrupt code goes here
}

The new macro is backwards compatible with the old - if no attributes are specified, the ISR will default to ISR_BLOCK, as is the norm without the new macros.

Just another suggestion and tool from a fellow lowly GCC C programmer :). Discuss and poke fun at at will.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

Last Edited: Mon. Apr 7, 2008 - 11:19 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Dean,

Very good work and sure to be helpful.

Thanks,
Smokey

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks Smokey! I appreciate that this will be viewed as either unnessesary, voodoo or silly by many, but I actually prefer this construct and if it helps someone, then my work isn't wasted. I like sharing and thinking up new ideas!

Speaking of which, wern't you trying to design some new header to help newbies with C? Has anything come from that?

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Well, yeah, but between the day job and juggling chainsaws, it is going kind of slow.

And this is the way tutorials get OT real quick so I'll just say that I intend to keep you informed and will email you with details as I progress.

Smiley

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Well, may it be worth to mention possible need of avr-libc-1.4.4 to avoid probable pitfalls?

Quote:
*** Changes in avr-libc-1.4.4:
* Bugs fixed:
...
[#15732] interrupt.h: ISR() incompatibility with gcc 3.4.5

http://www.nongnu.org/avr-libc/NEWS.txt

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

skleroz,

How so? My code redefines the ISR macro, and so should work regardless of what ISR is already set to. It shouldn't be affected by any existing ISR macro definition.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yes, I see. But if You are explaining (as it seems to me - not for "seasoned GCC users ") how an ISR(VectorName) was born

Quote:
Knowing that this was a great source of confusion - mainly due to the large amount of problems posted in the GCC section of this site - the developers of AVRLibC deprecated both macros and replaced it with a single new one:

ISR(VectorName) 
{ 
// Code goes here 
}


why not to provide some (usefull?) info, helping
Quote:
newbies don't make mistakes

At least before the new WinAVR release is out...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I'm still unclear. You want me to explain what the original ISR macro does? Or you think that my solution is a bad one?

I'll be happy to provide an explanation on any of this, just give me a clear rundown on what you're confused about.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
You want me to explain what the original ISR macro does? Or you think that my solution is a bad one?

1) No. Your introduction is thorough enough.
2) No. (BTW - which line of my post made You think so?)

You see, this forum even by it's name ("AVR Tutorials") is especially attractive for newbies...
One can even find out about ISR(VectorName) first time from Your post, but not from avr-libc manual (sigh) :(
So what would go wrong if this part of Your post would be appended with some comment like this (brown)

Quote:
Knowing that this was a great source of confusion - mainly due to the large amount of problems posted in the GCC section of this site - the developers of AVRLibC deprecated both macros and replaced it with a single new one:

ISR(VectorName) 
{ 
// Code goes here 
} 

(* If You are going to use ISR(VectName) macro it may be worth to update to avr-libc version 1.4.4 due to some bugfix concerning ISR() incompatibility with gcc 3.4.5)

Seems I need to continue "read-only" mode - my "not native English" does not allow me to communicate in clear way :(

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ahhh! I got you. I've appended the nessesary text to my original post. Sorry for the confusion!

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I've just updated the code so that it now supports GCC4.x with the global code compression turned on, a feature which normally ends up in deleted ISRs without the extra attributes.

Thanks to Bernd Trog, who suggested the extra attributes to me in a private email.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

skleroz wrote:
One can even find out about ISR(VectorName) first time from Your post, but not from avr-libc manual (sigh) :(

Methinks you have an outdated copy of the avr-libc manual then. I just looked at the 1.4.3 PDF and section 5.25 that documents tells you all about ISR()

Cliff

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Cliff, I must quote myself again:

Quote:
Seems I need to continue "read-only" mode - my "not native English" does not allow me to communicate in clear way :(

In no way I was blaming avrl-libc manual missing ISR() explanation.
All I was thinking about was that at least I know a couple of guys, who are mainly reading AVRFreaks, but (alas :( ) not the avr-libc manual...
They are completely new to avr'ing, and due to their boyhood are also ignoring forum search (as I can predict Your next question).

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I know what you mean - about 99.9% of all questions raised on 'Freaks are actually answered by the documentation (either the Datasheets, the Studio help, a copy of Kerningham&Ritchie, sundry other PDFs or a thread search/Google). It's a shame that some folks seem to think it's possible to learn to program without doing a bit of reading.

Cliff

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

It's what they are doing now - a bit of reading...
All I hope is that some day they would realize that they must do a lot of reading, searching and thinking!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:
I know what you mean - about 99.9% of all questions raised on 'Freaks are actually answered by the documentation (either the Datasheets, the Studio help, a copy of Kerningham&Ritchie, sundry other PDFs or a thread search/Google). It's a shame that some folks seem to think it's possible to learn to program without doing a bit of reading.

Cliff

hahahah classic who here ever thought reading would come in handy though really......

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Just updated this. I've added in the ISR_ALIAS attribute which will be available in GCC4.2. That will make it easier to alias the ISR code for one or more vectors to another vector's code.

Also added in some voodoo to allow for backwards compatibility. You can now use your existing code without changes without compile errors. This relies on the fact that the INTERRUPT attribute augments the SIGNAL attribute without being clobbered.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!