AVR-GCC-Tutorial/Alte Quellen

Aus der Mikrocontroller.net Artikelsammlung, mit Beiträgen verschiedener Autoren (siehe Versionsgeschichte)
Wechseln zu: Navigation, Suche

Einige Funktionen aus früheren Versionen der avr-libc werden inzwischen als veraltet angesehen. Sie sind nicht mehr vorhanden oder als deprecated (missbilligt) ausgewiesen und Definitionen in <compat/deprecated.h> verschoben. Es empfiehlt sich, vorhandenen Code zu portieren und die alten Funktionen nicht mehr zu nutzen, auch wenn diese noch zur Verfügung stehen.

Veraltete Funktionen zur Deklaration von Interrupt-Routinen

Die Makros SIGNAL und INTERRUPT zur Definition von Interruptroutinen sollten nicht mehr genutzt werden.

In aktuellen Versionen der avr-libc werden Interruptroutinen, die nicht durch andere Interrupts unterbrechbar sind, mit ISR deklariert, siehe Programmieren_mit_Interrupts im Hauptteil. Auch die Benennung wurden vereinheitlicht und an die üblichen Bezeichnungen in den AVR-Datenblättern angepasst. In der Dokumentation der avr-libc sind alte und neue Bezeichnungen in der Tabelle gegenübergestellt. Die erforderlichen Schritte zur Portierung:

  • #include avr/signal.h entfernen
  • SIGNAL durch ISR ersetzen
  • Name des Interrupt-Vektors anpassen (SIG_* durch entsprechendes *_vect)

Als Beispiel für die Anpassung zuerst ein "alter" Code:

#include <avr/interrupt.h>
#include <avr/signal.h>

/* Timer2 Output Compare bei einem ATmega8 */
SIGNAL (SIG_OUTPUT_COMPARE2)
{
   ...
}

Im Datenblatt wird der Vektor mit TIMER2 COMP bezeichnet. Die Bezeichnung in der avr-libc entspricht dem Namen im Datenblatt, Leerzeichen werden durch Unterstriche (_) ersetzt und ein _vect angehängt:

#include <avr/interrupt.h> 

ISR(TIMER2_COMP_vect)
{
   ...
}

Bei Unklarheiten bezüglich der neuen Vektorlabels hilft (noch) ein Blick in die Headerdatei des entsprechenden Controllers. Für das vorherige Beispiel also der Blick in die Datei iom8.h für den ATmega8, dort findet man die veraltete Bezeichnung unterhalb der aktuellen.

/* $Id: iom8.h,v 1.13 2005/10/30 22:11:23 joerg_wunsch Exp $ */
/* avr/iom8.h - definitions for ATmega8 */

...

/* Timer/Counter2 Compare Match */
#define TIMER2_COMP_vect		_VECTOR(3)
#define SIG_OUTPUT_COMPARE2		_VECTOR(3)
...

Für unterbrechbare Interruptroutinen, die mittels INTERRUPT deklariert sind, gibt es keinen direkten Ersatz in Form eines Makros. Solche Routinen sind laut Dokumentation der avr-libc in folgender Form zu deklarieren:

void XXX_vect(void) __attribute__((interrupt));
void XXX_vect(void)
{
  ...
}

Beispiel alt:

#include <avr/io.h>
#include <avr/interrupt.h>

INTERRUPT (SIG_OVERFLOW0)
{
   ...
}

Beispiel neu:

#include <avr/io.h>

void TIMER0_OVF_vect(void) __attribute__((interrupt));
void TIMER0_OVF_vect(void) 
{
   ...
}

Will oder kann man den Code nicht portieren, ist zur weiteren Verwendung von INTERRUPT die Header-Datei compat/deprecated.h einzubinden. Man sollte bei dieser Gelegenheit jedoch nochmals überprüfen, ob die Funktionalität von INTERRUPT tatsächlich gewollt ist. In vielen Fällen wurde INTERRUPT genutzt, wo eigentlich SIGNAL, also nunmehr ISR hätte genutzt werden sollen.

Veraltete Funktionen zum Portzugriff

inp und outp zum Einlesen bzw. Schreiben von Registern sind nicht mehr erforderlich, der Compiler unterstützt dies ohne diesen Umweg.

unsigned char i, j;

  // alt:
  i = inp(PINA);
  j = 0xff;
  outp(PORTB, j);

  // neu (nicht mehr wirklich neu...):
  i = PINA
  j = 0xff;
  PORTB = j;

Will oder kann man den Code nicht portieren, ist zur weiteren Verwendung von inp und outp auch hier ein

#include <compat/deprecated.h>

möglich.

Veraltete Funktionen zum Zugriff auf Bits in Registern

cbi und sbi zum Löschen und Setzen von Bits sind nicht mehr erforderlich, der Compiler unterstützt dies ohne diesen Umweg. Die Bezeichnung ist ohnehin irreführend da die Funktionen nur für Register mit Adressen im unteren Speicherbereich tatsächlich in die Assembleranweisungen cbi und sbi übersetzt werden.

  // alt:
  sbi(PORTB, PB2);
  cbi(PORTC, PC1);

  // neu:
  PORTB |=  (1<<PB2);
  PORTC &= ~(1<<PC1);

Will oder kann man den Code nicht portieren, ist zur weiteren Verwendung von sbi und cbi wiederum ein

#include <compat/deprecated.h>

notwendig.

Selbstdefinierte, nicht-standardisierte, ganzzahlige Datentypen

Auf selbstdefinierte Typdefininitionen und Makros für Integer-Types wie BYTE oder WORD sollte dringend verzichtet werden:

  • Diese Bezeichner sind nicht standardisiert.
  • Die Großschreibung der Bezeichner suggeriert Makros, aber es handelt sich dabei durchaus um Typedefs, deren Vorhandensein nicht überprüft werden kann, um Mehrfachdefinitionen auszuschliessen.
  • Es nicht a priori klar, ob ein WORD nun 16 Bits umfasst oder 32 – was ja gerade Sinn und Zweck solcher Festlegungen sein sollte. Die Definitionen sind plattformabhängig.

Stattdessen gibt es in C99 den Header

#include <stdint.h>

Erklärungen finden sich in der Dokumentation zu dem Header und auch im Abschnitt Ganzzahlige (Integer) Datentypen im Hauptteil.

eeprom.h ohne EEMEM

In älteren Versionen der AVR-LibC ist EEMEM noch nicht vorhanden, und man kann sich folgendermassen behelfen:

#include <avr/eeprom.h>

#ifndef EEMEM
#define EEMEM __attribute__((__section__(".eeprom")))
#endif