Plus d'info sur l'utilisation des Timer par l'environnement Arduino

Bonjour à tous,

Je débute depuis quelques mois, et je voudrais utiliser les Timers, mais comme un grand, en équilibre sur les registres et sans les petites librairies !! :slight_smile:

Mais voila, je n'arrive pas à trouver sur le site Arduino l'information que je cherche :

Comment l'environnement Arduino utilise les timer/counter de l'Atmega ??
J'ai cru comprendre que les micros() & millis() utilise le Timer0... mais quoi d'autre ? comment toucher un timer en sachant précisément quelle commande on "neutralise" ?

Sev

tout ce trouve dans des doc plus poussé, celle du composant, ATmega328 ou autre je ne sais pas quel carte tu utilise..

Skizo !

Yep!

La documentation de base est le datasheet du composant (prendre la version pdf complète, quelques Mo).

Pour info, il y a de trés bon tuto écrit par Dean Camera ici :

Faut pas avoir peur de l'anglais off-course XD

@+

Zoroastre.

D'après Advanced Arduino: direct use of ATmega counter/timers, seul le 1er timer 8bits (timer0) est utilisé.

Si tu cherche des informations sur l'utilisation directe des timers, je te recommande de lire la partie "timer0" de la datasheet(Il te faudra par fois aler chercher des infos dans d'autres sections. Par exemple, pour activer la sortie PWM après avoir modifier un timer, il te faudras modifier le Data Direction Registery [ou quelque chose dans le genre], ce qui revien à passer la patte en mode output.)
Une fois la datasheet assimilé, tu remarqueras que la libavr (utilisé par arduino) défini toute les constantes que tu a pu lire dans la datasheet. Cherches quelques exemples d'utilisation sur internet (du genre 'timers atmega328p') :wink:

Si tu veux savoir si une fonctionnalité précise est affectée (par exemple les libs de contrope I2C, ou autre) le plus simple et de feuilleter le code de la dite lib, et de vérifier qu'elle n'utilise pas interruption ou de compteur associé à ton timer.

Premièrement : merci à tous !

Les 2 liens qui m'aident beaucoup sont les suivants :

http://www.mythic-beasts.com/~markt/ATmega-timers.html
http://deans-avr-tutorials.googlecode.com/svn/trunk/Timers/Output/Timers.pdf

On y apprend que seul le timer0 est utilisé par micros(), millis(), delay()... et que le timer1 est utilisé par la librairie servo.
J'imagine que le timer0 tourne à 250 KHz puisque la résolution du compteur micros() est de 4µs...

Le timer1 a l'air plus flexible (A & B) et plus contenant (16 bits)...

Donc je partirais bien sur l'idée de me monter un timer1 pour mes besoins personnels. (voir mon projet ici : Programing my Arduino to listen my receiver - Page 2 - RC Groups mais en anglais)

Mais alors comment "neutraliser" les interruptions mise en place par l'arduino sur le timer0 ?
Cette partie ne parait pas documentée.

La datasheet de l'Atmega 328P, je la lis souvent mais elle ne parle évidement pas de l'arduino :wink:

EDIT : Je viens de trouver ceci :
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1216294585
Qui me laisse penser que wiring.c est contient ce que je cherche... cela veut-il dire que ce fichier est inclus automatiquement à chaque compilation ?

À quel fréquence veut tu utiliser ton interruption? Le mode fast pwm, qui permet d'avoir une interruption OVF (counter overflow) monte à 62,5kHz, soit toute les 16uS (Le compteur est incrémenté à chaque cycle, donc à 16MHz). Tu peux bien sur diminuer le tout en utilisant des interruptions comme CMPA ou CMPB (avr-libc: <avr/interrupt.h>: Interrupts pour la liste des interruptions) mais n’oublie pas qu’avec de tels fréquences, le nombre d'instructions que tu a le temps d’exécuter n'est pas folichon...
Pour un entête de fonction utilisé comme interruption (c'est à dire une fonction vide), tu utilise déjà une vingtaine de cycles, donc ça vas très vite.

Pour savoir comment remplacer une interruption 'à chaud', ou simplement à la compilation, tu trouveras ce qu'il faut dans la doc de la libavr (il s'agit essentiellement de stocker l'adresse de ton interruption dans le bon emplacement de la mémoire de ton atméga).

La datasheet sert surtout pour savoir quels sont les modes des counters, comment les utiliser, quels sont les interruptions disponibles, etc.

j'utilise beaucoup les timers de l'arduino, c'est super puissant mais ça m'a pris plusieurs jours de lecture du datasheet, et plusieurs pages de brouillon. Mais ça vaut le coup de s'y intéresser (surtout sur la MEGA où on a accès à 4 timers 16 bits + 2 x 8 bits complètement indépendants). Une fois qu'on a bien compris comment utiliser les trois registres de configuration d'un timer, tout est permis. l'atmega est très polyvalent, du coup, les configs sont pas évidentes mais utiles.

Bon arrachage de cheveux!

Cinci

salut,

Super_Cinci:
j'utilise beaucoup les timers de l'arduino, c'est super puissant mais ça m'a pris plusieurs jours de lecture du datasheet, et plusieurs pages de brouillon. Mais ça vaut le coup de s'y intéresser (surtout sur la MEGA où on a accès à 4 timers 16 bits + 2 x 8 bits complètement indépendants). Une fois qu'on a bien compris comment utiliser les trois registres de configuration d'un timer, tout est permis. l'atmega est très polyvalent, du coup, les configs sont pas évidentes mais utiles.

Je plussoie, les timers sont trés puissant une fois leur fonctionnement assimilé, et pas seulement avec les ATmega :wink:
Exemple avec un ATtiny85 : [ATtiny] Générateur de signaux DDS (DAC software) | Skyduino - Le DIY à la française

Mais pour ça il faut ce éplucher tout le datasheet et lire tout même (surtout) les petites lignes :wink:

Salut,

Je rejoins la conversation car ce souci s'est posé il y a quelques mois lorsque nous préparions la coupe de robotique, à savoir: qu'utilise l'arduino pour fonctionner?

Donc si je résume ce que je viens de lire, si l'on utilise ni analogWrite() ni la librairie servo, on peut se permettre d'utiliser tous les timers (sauf le timer 0) avec "le code AVR"? c'est à dire interruptions softs et autres joyeusetés (ISR overflow?)

ça m'intéresserait vraiment de la savoir car je pense à utiliser des Arduino pour leur fiabilité hardware mais du code AVR pour son niveau plus bas...

En tout cas je suis le fil avec intéret!

Et si tu n'utilise pas les fonctions delay/ms et que tu fait tout à la main, tu peux utiliser tout les timers :wink:

Zenol:
Et si tu n'utilise pas les fonctions delay/ms et que tu fait tout à la main, tu peux utiliser tout les timers :wink:

Effectivement! Il faut savoir que chaque port série a son propre timer, le WD aussi, et l'utilisation des trois timers du UNO n'affectera personne d'autre que les fonctions pompeuses analogWrite(), delay(), millis(), etc du core arduino... que l'on n'utilise finalement que très peu et dont on peut se passer surtout si on a un DS1307 en RTC externe. Il en va de même pour les INT et PCINT.

En utilisant judicieusement les INT externes et timers, le core arduino peut retourner se coucher.

Super_Cinci:
Effectivement! Il faut savoir que chaque port série a son propre timer, le WD aussi, et l'utilisation des trois timers du UNO n'affectera personne d'autre que les fonctions pompeuses analogWrite(), delay(), millis(), etc du core arduino... que l'on n'utilise finalement que très peu et dont on peut se passer surtout si on a un DS1307 en RTC externe. Il en va de même pour les INT et PCINT.

Et quand on découvre <util/delay.h> on n'as même plus besoin de ce casser la tête :wink:
http://www.nongnu.org/avr-libc/user-manual/group__util__delay.html

Super_Cinci:
En utilisant judicieusement les INT externes et timers, le core arduino peut retourner se coucher.

Des fois je me dit que coder en "arduino" est vraiment pas plus compliqué que coder en Avr-C ...
Franchement la team arduino ferait une doc des registres/macro/fonctions les plus utilisé ça passerai comme une lettre à la poste

Ouaaouu,

Le sujet passionne les foules !!

Zenol:
À quel fréquence veut tu utiliser ton interruption?

Je souhaite mesurer les signaux d'un recepteur de modelisme (6 voies), ce sont des pseudo PWM avec un état haut qui varie entre 1000µs et 2000µs (point milieu à 1500µs), et j'aimerai les mesurer avec une précision de 1µs.

Je dois générer 4 voies de sortie de même type (signal servo).

Plus de précision sur mon projet ici, but in Anglishe :

(j'aimerai l'héberger ailleurs mais je ne sais pas encore où...)

skywodd:
Des fois je me dit que coder en "arduino" est vraiment pas plus compliqué que coder en Avr-C ...
Franchement la team arduino ferait une doc des registres/macro/fonctions les plus utilisé ça passerai comme une lettre à la poste

On peut uiliser une Adruino duemilanove sans l'environnement arduino ?

skywodd:
Et quand on découvre <util/delay.h> on n'as même plus besoin de ce casser la tête :wink:
avr-libc: <util/delay.h>: Convenience functions for busy-wait delay loops

J'ai pas encore tout bien compris mais je sens que cette librairie pourrait être l'étape intermiédiaire pour moi entre la librairie servo et le codage direct avec les registres...

Super_Cinci:
...sur la MEGA où on a accès à 4 timers 16 bits + 2 x 8 bits complètement indépendants

Indépendants oui et non, ils dépendent quelque par un peu les uns des autres.
L'utilisation du timer0 par l'environnement Arduino "consomme" du temps de proc par le biais d'interruption... si mon interruption intervient simultanément mais arrive après dans la file, je vais devoir attendre et ma mesure de temps sera faussée, je ferai donc mieux de "démonter" l'utilisation du timer0 de l'environnement Arduino... non ?

Sev

UniseV:
On peut uiliser une Arduino duemilanove sans l'environnement arduino ?

Bien sur, une carte arduino c'est avant tout un bête ATmega :wink:
Il suffit de savoir utiliser les outils en ligne de commande, comme avrdude par exemple :wink:

UniseV:
J'ai pas encore tout bien compris mais je sens que cette librairie pourrait être l'étape intermiédiaire pour moi entre la librairie servo et le codage direct avec les registres...

Ce n'est pas vraiment une librairie c'est juste une série de fonctions permettant de créer des delais de quelque us à quelques ms.
Un peu comme delay() et delayMicroseconds() mais en plus léger et en moins usine à gaz.

UniseV:
L'utilisation du timer0 par l'environnement Arduino "consomme" du temps de proc par le biais d'interruption... si mon interruption intervient simultanément mais arrive après dans la file, je vais devoir attendre et ma mesure de temps sera faussée, je ferai donc mieux de "démonter" l'utilisation du timer0 de l'environnement Arduino... non ?

Regarde du côté des macro sei() et cli() qui permettent d'activer / désactiver les interruptions durant une autre interruption ou dans le code principal.

Justement, ces commandes (sei et cli), dont j'utilise le pendant en C dans mon main loop pour empecher mes fonctions d'interruption de mettre à jour les données que je lis (notament pour les données plus grandes que 8bits) me posent des interrogations internes :

Ces "pause" concernent quel types interruptions ?
Les compteurs continuent de s'incrémenter normalement ? (l'incrémentation des compteurs c'est bien fait par une interruption ?)
Et les interruption de type counter overflow, elle peuvent intervenir ?
Toutes les interruptions qui auraient du arrivent pendant cette période sont-elle jetées à la poubelle ou certaines sont-elles mises en file d'attente ?

Je relis régulièrement la datasheet du 328P sur ces points, et je ne suis pas toujours éclairé.

Sev

UniseV:
Ces "pause" concernent quel types interruptions ?

Toute les interruptions quels quelle soit, de type ISR (ou anciennement SIGNAL).

UniseV:
Les compteurs continuent de s'incrémenter normalement ?

Les compteurs TCNxx sont directement relié à l'horloge du microcontrôleur.
Ils s'incrémentent tant que leurs prescaler les reliant à l'horloge du µc est différent de 0 (0 = déconnecté de l'horloge).

UniseV:
(l'incrémentation des compteurs c'est bien fait par une interruption ?)

Non c'est matériel, il n'y as pas d'interruptions.
Si il devait y avoir une interruption à chaque tick de l'horloge cpu on ne pourrais rien faire :wink:

UniseV:
Et les interruption de type counter overflow, elle peuvent intervenir ?

Non, l'interruptions sera généré mais le morceaux de code lié ne sera pas appelé par le cpu.
SEI et CLI permettent d'autorisé ou d'interdire toute les interruptions au niveau du cpu.

UniseV:
Toutes les interruptions qui auraient du arrivent pendant cette période sont-elle jetées à la poubelle ou certaines sont-elles mises en file d'attente ?

Elles sont ignoré comme si elles n'avait jamais existé, les compteurs continue de s'incrémenter sans rien faire d'autre, etc ...

Merci à tous, la brume se dissipe.

Finalement, au niveau des timer/counter, le "core arduino" ne consomme pas de ressource, il ne fait que paramétrer le timer0 pour ses besoins.

Je peux donc disposer à ma guise des 3 timers à partir du moment ou je n'utilise pas les fonctions suivantes :
micros(), millis(), delay(), analogWrite() qui utilise le timer0
La librairie Servo qui utilise le timer1

Sev

analogWrite() qui utilise le timer0

Je n'avais pas compris comme cela , (mais c'est pas pour autant que j'ai raison) :
Merci d'avoir lancé ce sujet il est très intéressant.

• INT1/OC2B/PCINT19 – Port D, Bit 3
INT1, External Interrupt source 1: The PD3 pin can serve as an external interrupt source.
OC2B, Output Compare Match output: The PD3 pin can serve as an external output for the
Timer/Counter0 Compare Match B. The PD3 pin has to be configured as an output (DDD3 set
(one)) to serve this function. The OC2B pin is also the output pin for the PWM mode timer
function.
PCINT19: Pin Change Interrupt source 19. The PD3 pin can serve as an external interrupt
source.

• MOSI/OC2/PCINT3 – Port B, Bit 3
MOSI: SPI Master Data output, Slave Data input for SPI channel. When the SPI is enabled as a
Slave, this pin is configured as an input regardless of the setting of DDB3. When the SPI is
enabled as a Master, the data direction of this pin is controlled by DDB3. When the pin is forced
by the SPI to be an input, the pull-up can still be controlled by the PORTB3 bit.
OC2, Output Compare Match Output: The PB3 pin can serve as an external output for the
Timer/Counter2 Compare Match. The PB3 pin has to be configured as an output (DDB3 set
(one)) to serve this function. The OC2 pin is also the output pin for the PWM mode timer
function.

A ce que je comprend de la datasheet j'ai l'impression que la pmw obtenue à partir du port B utilise le timer 2 et que celle obtenue à partir du port C utilise le timer 0.
En fait il faudrait un timer différent par port.
Les deux sont des timers 8 bits, seul le timer 1 (16bits) semble totalement libre.

Aurais-je raison ou me mettais-je le doigt dans l'oeil jusqu'au coude ?

skywodd:

UniseV:
Toutes les interruptions qui auraient du arrivent pendant cette période sont-elle jetées à la poubelle ou certaines sont-elles mises en file d'attente ?

Elles sont ignoré comme si elles n'avait jamais existé, les compteurs continue de s'incrémenter sans rien faire d'autre, etc ...

Sauf si je me trompe, mais il me semble que le flag "interrupt" de chaque interruption est mis à 1 lorsque se produit l'évènement correspondant, ce flag n'est mis à 0 que si on écrit un 1 dedans ou dès le traitement de l'INT, ce qui fait que quand on fait un SEI() (ou en sortie d'ISR), toutes les interruptions intervenues pendant le CLI() sont traitées les unes après les autres, dans l'ordre d'importance (et non d'arrivée).

Pour ton projet, ça fait un paquet de choses à compter, je te conseillerais la mega, car les PCINT ne sont utiles que si on les traite tout de suite (il se peut que le signal ait disparu entre l'interruption et la lecture du port, dans ce cas, tu n'auras pas moyen de savoir qui a déclenché la PCINT).

Je maintiens que les timers sont indépendants, la seule chose qui les relie est le prescaler. lorsqu'on reset le prescaler, tous les timers auront un temps de retard ou d'avance sur le départ de comptage suivant (le prescaler est un bête compteur 10 bits avec l'horloge CPU en entrée (16MHz)...). Tu peux même configurer un timer pour compter les impulsions sur une pin (Tn ou n est le numéro du timer), ça se fait matériellement, et ça permet de déclencher des int (COMPA, CMPB, OVF...)au bout d'un certain nombre d'impulsions... ou encore de relever la valeur du comptage au bout d'un temps précis pour connaître la fréquence de tes impulsions. pour le comptage d'impulsion, c'est super intéressant! mais seul la broche T5 du mega est routée, les autres entrées des timers sont pas accessibles, c'est vraiment dommage, voir nul.

68tjs:

analogWrite() qui utilise le timer0

Je n'avais pas compris comme cela , (mais c'est pas pour autant que j'ai raison) :
Merci d'avoir lancé ce sujet il est très intéressant.

...Datasheet Atmega328P...

Aurais-je raison ou me mettais-je le doigt dans l'oeil jusqu'au coude ?

Je pense que nous ne parlons juste pas de la même chose, je parlais de l'utilisation faite des timer par le "core arduino", tu ne trouveras rien à ce sujet dans la Datasheet de l'Atmega, parce que Atmega ne sait pas ce que Arduino fait avec son controlleur :wink:

Super_Cinci:
Sauf si je me trompe, mais il me semble que le flag "interrupt" de chaque interruption est mis à 1 lorsque se produit l'évènement correspondant, ce flag n'est mis à 0 que si on écrit un 1 dedans ou dès le traitement de l'INT, ce qui fait que quand on fait un SEI() (ou en sortie d'ISR), toutes les interruptions intervenues pendant le CLI() sont traitées les unes après les autres, dans l'ordre d'importance (et non d'arrivée).

Ok il faudra que je sois vigilant sur ce point.

Super_Cinci:
Pour ton projet, ça fait un paquet de choses à compter, je te conseillerais la mega, car les PCINT ne sont utiles que si on les traite tout de suite (il se peut que le signal ait disparu entre l'interruption et la lecture du port, dans ce cas, tu n'auras pas moyen de savoir qui a déclenché la PCINT).

Je ne compte interrompre les interruptions ( :roll_eyes:) que une fois par trame (après la réception du dernier front), et ce uniquement dans le but de relever les valeurs, je pense sincèrement que cette "coupure" peut être légère, courte et bien positionnée.... mais ça reste bien sûr à verifier.

Je crains beaucoup plus pour la partie de recopie des canaux avec 5ms d'ecart, parce que la seule solution que j'ai trouvé pour le moment c'est qu'une interruption "ordonance" une autre interruption... tout ça avec une précision de 1 µs. :sweat_smile:

Sev