Club robotique de Sophia-Antipolis

Accueil > POBOTpedia > Programmation > Apprendre à coder > Les micro-contrôleurs > Trucs et astuces > AVRlib et les timers des ATmega168

AVRlib et les timers des ATmega168

samedi 31 janvier 2009, par Julien H.

Les microcontrôleurs AVR ATmega d’Atmel sont utilisés sur beaucoup de projets par des débutants tout comme par des experts. On avait l’habitude d’utiliser les ATmega8, ATmega16 ou ATmega32, jusqu’à ce que de nouveaux ATmega viennent compléter la famille : ce sont des dérivés de l’ATmega8 (c’est à dire qu’ils ont des fonctionnalités similaires en terme de nombre d’entrées/sorties pour faire simple), mais ils ont plus de mémoire (4, 8 ou 16 au lieu des 2 kbits selon que vous utilisiez un ATmega48, ATmega88 ou ATmega168).

On pourrait généraliser en parlant de ATmegaxx8, mais attention ! l’Atmel ATmega128 n’en fait pas partie, c’est un gros AVR (ATmega32, ATmega64 donc ATmega128 très logiquement).

Cet article est destiné à exposer le problème de compilation qu’on rencontre en utilisant AVRlib quand on passe d’un ATmega8 à un ATmega168. Et d’apporter la solution bien sûr :)

Le problème

On prend un code très simple utilisant un ATmega8, la bibliothèque de code gérant les timers de l’AVR disponible dans AVRlib et on utilise WinAVR (avr-gcc) pour compiler :


//----- Include Files ---------------------------------------------------------
#include "avr/io.h" // include I/O definitions (port names, pin names, etc)
#include "avr/interrupt.h" // include interrupt support

#include "global.h" // include our global settings
#include "timer.h" // include timer function library (timing, PWM, etc)

/*
*
*
*
*/
int main(void)

timerInit() ;

while (1)

// votre code ici
timerPause(500) ;

return 0 ;

Tout se passe bien, on compile avec le makefile du projet ci-joint et c’est fini.

PNG - 21.4 ko
Compilation ATmega8 OK

Maintenant on change pour utiliser un ATmega168. Il faut modifier le makefile et parfois le fichier global.h si jamais on en profite aussi pour utiliser un quartz plus gros.

Et on recompile : voici l’erreur (celle qui a dû vous amener sur cette page).

> "make.exe" all
avr-gcc -c -g -Os -Wall -Wstrict-prototypes -IC:\Langages\AVRLib -Wa,-ahlms=test.lst -mmcu=atmega168 -I. test.c -o test.o
avr-gcc -c -g -Os -Wall -Wstrict-prototypes -IC:\Langages\AVRLib -Wa,-ahlms=C:\Langages\AVRLib/timer.lst -mmcu=atmega168 -I. C:\Langages\AVRLib/timer.c -o C:\Langages\AVRLib/timer.o
C:\Langages\AVRLib/timer.c: In function `timer0Init':
C:\Langages\AVRLib/timer.c:98: error: `TIMSK' undeclared (first use in this function)
C:\Langages\AVRLib/timer.c:98: error: (Each undeclared identifier is reported only once
C:\Langages\AVRLib/timer.c:98: error: for each function it appears in.)
C:\Langages\AVRLib/timer.c: In function `timer1Init':
C:\Langages\AVRLib/timer.c:109: error: `TIMSK' undeclared (first use in this function)
C:\Langages\AVRLib/timer.c: In function `timer2Init':
C:\Langages\AVRLib/timer.c:118: error: `TIMSK' undeclared (first use in this function)
C:\Langages\AVRLib/timer.c: In function `timer0SetPrescaler':
C:\Langages\AVRLib/timer.c:127: error: `TCCR0' undeclared (first use in this function)
C:\Langages\AVRLib/timer.c: In function `timer2SetPrescaler':
C:\Langages\AVRLib/timer.c:140: error: `TCCR2' undeclared (first use in this function)
C:\Langages\AVRLib/timer.c: In function `timer0GetPrescaler':
C:\Langages\AVRLib/timer.c:147: error: `TCCR0' undeclared (first use in this function)
C:\Langages\AVRLib/timer.c: In function `timer2GetPrescaler':
C:\Langages\AVRLib/timer.c:163: error: `TCCR2' undeclared (first use in this function)
C:\Langages\AVRLib/timer.c: At top level:
C:\Langages\AVRLib/timer.c:464: warning: `SIG_OUTPUT_COMPARE2' appears to be a misspelled signal handler
make.exe: *** [C:\Langages\AVRLib/timer.o] Error 1

> Process Exit Code: 2
> Time Taken: 00:01

En fait, le registre TIMSK et les autres cités dans le message ne sont pas présents dans l’ATmega168, ce n’est pas juste la taille de la mémoire qui a changé mais aussi le fonctionnement interne, les registres et même le bootloader interne etc.. On ne peut jamais faire passer un ATmega168 pour un ATmega8 lors de la programmation.

Donc il ne faut plus utiliser la bibliothèque "timer" d’AVRlib. Attention, ne modifiez jamais le code source, Pascal Stang (l’auteur d’AVRlib) a pensé à nous et il propose deux autres versions de gestion des timers. Si on lisait la doc on s’en serait aperçu :) mais on est tous pareils.

PNG - 10.2 ko
Liste des bibliothèques "timer" d’AVRlib

Il faut donc remplacer "timer.h" et "timer.c" par "timerx8.h" et "timerx8.c". Il y a même une troisième version pour les timers des ATmega128 !

Voici le nouveau code :

#include "global.h" // include our global settings
#include "timerx8.h" // include timer function library (timing, PWM, etc)

On peut même écrire un code qui s’adapte au microcontrôleur que vous utilisez, sans avoir à modifier tous vos fichiers source (utile pour distribuer du code). Merci au support de Devtronic (myAVR) pour cette astuce :


#include "global.h"
#ifndef _AVR_IOMX8_H_
// Atmega8 et autres "classiques"
#include "timer.h"
#else
// Atmega48/88/168
#include "timerx8.h"
#endif

Il faut de toute façon toujours penser aussi à modifier le makefile à deux endroits : la déclaration de l’utilisation de cette lib (si on laissait toutes les libs possible, le code serait énorme), et aussi la construction de la lib en fin de fichier :

...

#put your C sourcefiles here
#  Here you must list any C source files which are used by your target file.
#  They will be compiled in the order you list them, so it's probably best
#  to list $(TRG).c, your top-level target file, last.

        SRC = $(AVRLIB)/timerx8.c $(TRG).c

...

a2d.o                        : a2d.c                        a2d.h
timerx8.o                : timerx8.c                timerx8.h                global.h
pulse.o                : pulse.c                pulse.h                timerx8.h        global.h
lcd.o                        : lcd.c                        lcd.h                        global.h

...

Comme vous le constatez, non seulement la ligne anciennement "timer.o" mais aussi les autres libs qui utilisent "timer" (ici, "pulse").

Portfolio

  • Compilation ATmega168 OK

Un message, un commentaire ?

modération a priori

Attention, votre message n’apparaîtra qu’après avoir été relu et approuvé.

Qui êtes-vous ?

Pour afficher votre trombine avec votre message, enregistrez-la d’abord sur gravatar.com (gratuit et indolore) et n’oubliez pas d’indiquer votre adresse e-mail ici.

Ajoutez votre commentaire ici
  • Ce formulaire accepte les raccourcis SPIP [->url] {{gras}} {italique} <quote> <code> et le code HTML <q> <del> <ins>. Pour créer des paragraphes, laissez simplement des lignes vides.

Ajouter un document