TIMER0 Attiny84A [RESOLU]

Bonjour,

Je viens vers vous car je rencontre un problème avec mon Attiny84A.
Je souhaite utiliser le timer0 en mode normal (compteur).
Le but de ce programme t de faire clignoter une LED toutes les secondes. (je l'ai récupéré sur internet et adapté).
Or rien ne se passe (La LED reste simplement allumée). (Pas d'erreur de compilation). Je pense me tromper dans les registres mais pourtant je les ai bien adaptés avec la datasheet.

Pour compiler sur l'Attiny84A j'utilise la librairie de damellis.

Voici le Code :

// Clignotement d'une LED (mot anglais pour DEL) à 1 Hz par une 
// interruption en provenance du timer 0,


bool etat = 1;
 
void setup () {
  pinMode (3, OUTPUT);
  digitalWrite(3, HIGH);
  cli();                                // Désactive les intteruptions 
  bitClear (TCCR0A, WGM00);             // WGM00 = 0    
  bitClear (TCCR0A, WGM01);             // WGM01 = 0 
  bitClear (TCCR0A, WGM02);             // WGM02 = 0 
  TCCR0B = 0b00000100;                  // Clock / 256 soit 16 micro-s 
  TIMSK0 = 0b00000001;                  // Interruption locale autorisée par TOIE0
  sei();                                // Active les interruptions 
}
 
byte varCompteur = 0;       // La variable compteur
 
// Routine d'interruption
ISR(TIMER0_OVF_vect) 
{
  TCNT0 = 256 - 250; // 250 x 16 µS = 4 ms
  if (varCompteur++ > 125) 
  { // 125 * 4 ms = 500 ms (demi-période)
    varCompteur = 0;
    etat = !etat;
  }
}
 
void loop () 
{
 digitalWrite(3, etat);
}

Merci de vos retours !
Bonne journée.

Je n'ai pas analysé tout le code (paresse au début car il faut vérifier tous les registres...) mais, j'extrais ces lignes:

bool etat = 1;

void loop ()
{
 digitalWrite(3, etat);
}

Comme le compilateur ne sait pas que la variable etat peut voir sa valeur changée en dehors de la boucle, il est possible la variable soit mise dans un registre et ne soit pas évaluée à chaque tour. Il faut dire au compilateur que la variable peut évoluer en la déclarant volatile:

volatile bool etat = 1;

c'est une excellente piste, sachant que le booléen etat n'est modifié que dans l'ISR

allons plus loin : c'est aussi le cas de varCompteur ...

... mais allons encore plus loin : les 3 bits WGM ne sont peut-être pas localisés dans le même registre ?

(avant de me faire taper dessus)

pour WGM, ça ne change rien, il n'y a que superposition sur un bit réservé, et de toute façon ces 3 bits sont à '0' au démarrage, donc ils ne sont pas en cause.

mais pour la remarque de Vileroi, par contre ...

allons plus loin : c'est aussi le cas de varCompteur ...

Voici ce que dit la référence d'Arduino:

Une variable devra être déclarée volatile chaque fois que sa valeur pourra être changée par quelque chose d'autre que le code dans laquelle elle apparaît, tel qu'un fil d'exécution concurrent. Avec Arduino, la seule situation où cela risque d'arriver concerne les section de codes associées aux interruptions, appelées également routines de service des interruptions.

varCompteur n'est pas modifiée ailleurs que dans la procédure d'interruption. Il n'y a pas pour moi de raison de la déclarer volatile.

... mais allons encore plus loin : les 3 bits WGM ne sont peut-être pas localisés dans le même registre ?

Ils sont répartis sur 2 registres. C'est pour cela, je suppose qu'ils sont positionné séparément pour mieux mettre en évidence leur globlité.

Mais je me suis arrêté à etat car je pense que c'est déjà une condition suffisante pour que la led ne change pas d'état.

bonjour,

récrit pour AtmelStudio et testé sur un Uno (aucune modif du comportement que tu as écrit, juste une réécriture pour l'IDE d'Atmel) :

/*
 * essais-328.cpp
 *
 * Created: 13/07/2020
 * Author : françois
 */

// Clignotement d'une LED (mot anglais pour DEL) à 1 Hz par une
// interruption en provenance du timer 0,

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

uint8_t etat = 0b00100000; // à gérer comme un booléen placé sur PB5 = Pin13 = DEL
uint8_t varCompteur = 0; // La variable compteur

int main(void)
{
//void setup () {
 DDRB = 0b00100000 ; // pinMode (3, OUTPUT); PB5 = sortie, les autres en entrées
 PORTB = 255 ; // digitalWrite(3, HIGH); PB5 = '1' + pull-ups ailleurs
 // cli();                                // Désactive les intteruptions
 TCCR0A = 0b00000000 ;
 // bitClear (TCCR0A, WGM00);             // WGM00 = 0
 // bitClear (TCCR0A, WGM01);             // WGM01 = 0
 // bitClear (TCCR0A, WGM02);             // WGM02 = 0
 TCCR0B = 0b00000100;                  // Clock / 256 soit 16 micro-s
 TIMSK0 = 0b00000001;                  // Interruption locale autorisée par TOIE0
 sei();                                // Active les interruptions
//}

    while (1) // void loop ()
    {
 PORTB = (PORTB & 0b11011111) | etat ; // digitalWrite(3, etat);
 }
}


// Routine d'interruption
ISR(TIMER0_OVF_vect)
{
 TCNT0 = 256 - 250; // 250 x 16 µS = 4 ms
 if (varCompteur++ > 125)
 { // 125 * 4 ms = 500 ms (demi-période)
 varCompteur = 0;
 etat = (etat & 0b11011111) | ( (~ etat) & 0b00100000) ; // etat = !etat;
 }
}

résultat : dans ce cas très précis, ça fonctionne sans l'attribut volatile, je pense que c'est effectivement dû au fait que les variables ne soient modifiées que dans l'ISR.

si dans ton cas ça ne fonctionne pas, c'est probablement dû à des définitions Arduino : essaie d'utiliser directement les ports et de les manipuler à la main, on ne sait jamais.

mais malgré tout, quand tu utilises et manipules des variables dans une ISR, prend tout de même l'habitude de les déclarer volatile, ça évite les mauvaises surprises si plus tard, après une modif de code, tu oublies de le faire.

Bonjour,

C'est bizarre que tu arrives à compiler, moi lorsque j'essaie de compiler j'ai ce message d'erreur: multiple definition of `__vector_11'
Je suppose que c'est parce que l'interruption du timer0 est déjà utilisée par le core attiny84 pour la gestion de millis() et delay().

Pourquoi n'utilises tu pas delay() ou millis()?

@kamill,
salut, je n'utilise pas l'IDE Arduino (uniquement les cartes pour leur bootloader), mais AtmelStudio.

mais c'est vrai, j'ai (avant) tenté de compiler sous Arduino : j'ai eu une erreur évoquant un "__vector_16", mais avec une carte Uno.

Bonjour,

Premièrement je tiens à vous remercier pour toutes vos réponses.

Pour te répondre vileroi, il s'avère que changer la variable en variable volatile n'a pas résolu mon problème.
Comme la fait remarquer 5_cylindres, le programme fonctionne correctement sans la variable volatile.
Dans tous les cas je prends bonne note de ta remarque 5_cylindres et je vais laisser la variable en volatile.

Je n'ai pas encore essayé d'attaquer les registres des ports directement mais je vais m'y mettre.
A titre d'information j'ai compilé le programme "blink" et aucun problème.
J'ai oublié de préciser que j'avais compilé le programme sur un attiny85 en adaptant les registres et aucun problème.

@kamil, tu utilises quel librairies pour compiler sur les Attiny ?
Pour répondre à ta question, la c'est simplement un test pour vérifier le bon fonctionnement du timer0. Mais en réalité le programme est un peu plus complexe et l'utilisation de delay() n'est pas adaptée.

Etrange, je n'ai eu aucune erreur de compilation. Sachant que j'ai aussi essayer le Timer1 sans résultat. Je vais continuer de chercher dans cette voie-là.

Bonne journée à vous.

J'utilise le support attiny à cette url https://raw.githubusercontent.com/damellis/attiny/ide-1.6.x-boards-manager/package_damellis_attiny_index.json

il faudrait savoir comment Arduino intervient sur les timers, je veux dire : si les configurer à la main permet d'outrepasser ou non les réglages de l'IDE.

essaye d'écrire l'intégralité des registres TCCR0A/B pour forcer le mode en plus du prescaler.

en fait, récrit tous les registres tels que tu les veux : c'est peut-être ça qui coince, je ne sais pas quel est le mode utilisé pour des fonctions comme delay() ou millis().

Le premier code est bon, effectivement sous réserve que la bibliothèque utilisée n'a pas défini la routine ISR(TIMER0_OVF_vect).

Cela tourne correctement sur une UNO, les registres étant les mêmes, mais avec le timer 1 car TIMER0_OVF_vect est déjà défini.

bonsoir,

donc, au vu de ce que Vileroi fait remonter de ses essais, deux solutions : changer d'IDE, ou changer de timer.

pour ma part, j'ai déjà changé d'IDE il y a longtemps, reste à savoir si tu (7895tho) n'envisageais pas d'utiliser le timer1 pour autre chose.
mais si tu t'en sers tu n'auras plus toute cette cuisine à réaliser pour obtenir tes 500ms de demi-période ! vu qu'il est en 16 bits, il a une amplitude de plus de 4s.

[EDIT]
ça tourne très bien sur une carte Uno (328P) avec le timer0, mais pas sous Arduino : sous AtmelStudio (aucune fonctionnalité non désirée ne vient perturber mon utilisation des périphériques du µC).
[/EDIT]

Bonjour,

Je vous remercie pour vos réponses.

Je n'ai pas eu le temps de me poser sur le problème mais normalement je devrais être disponible demain après-midi ou ce week end.

Donc j'essaye de travailler avec le timer 1 comme vous me le recommandez.

Je pense dans un premier temps que changer de timer (vu qu'il n'est pas utilisé) et plus simple que changer d'IDE.
Mais sur du long terme je pense qu'il est plus intéressant de changer d'IDE.

Ca me fait penser à une question que je me suis posé dernièrement.
Elle sort un peu du topic, (peut-être que je devrais en créer un autre) mais comment peut-on contrôler une LED WS218B sans librairie.
Je me doute qu'il y a une trame à respecter, mais je n'ai pas plus de détail n'ayant pas commencé mes recherches.

Dans tous les cas je vous tiens informé sur mon avancement ! :wink:

Bonne journée.

bonjour,

je ne cherche pas du tout à te faire changer d'IDE, surtout si tu es en phase d'apprentissage : Arduino a été créé pour ça.

pour les DELs WS2812 sans bibli, j'ai essayé et me suis pris la tête, donc vite abandonné.
il faut gérer le temps avec précision car il n'y a pas d'entrée d'horloge : la vitesse de transfert doit être respectée, et c'est trop contraignant.

personnellement, je suis passé aux APA102 (plus chères que les WS2812, mais avec signal d'horloge) et ça me va mieux.

7895tho:
Je pense dans un premier temps que changer de timer (vu qu'il n'est pas utilisé) et plus simple que changer d'IDE.

Je ne comprend pas ce que tu veux faire. Soit tu utilises l'ide arduino et son framework et tu peux utiliser millis() donc tu n'as pas besoin d'un autre timer pour faire clignoter ta led, soit tu n'utilises pas le framework arduino et là rien ne t'interdit d'utiliser le timer0

7895tho:
mais comment peut-on contrôler une LED WS218B sans librairie.

Pourquoi tu veux controler des leds WS2812 sans librairie? Pour le chalenge?

La librairie d'Adafruit est supposée être compatible avec les attiny, mais dans mon souvenir je n'ai jamais réussi à la faire fonctionner sur attiny84.
Par contre dans les essais que j'avais faits, la librairie FastLed fonctionne sur attiny84.

Bonsoir,

Je vous remercie pour votre aide et je viens de trouver la solution à mon problème qui vous allez voir et très simple.

Avant tout, je vais répondre aux questions de Kamil.

Comme je l'ai précisé dans un précédent message, l'utilisation de millis() ou delay() n'est pas adapté. Ce programme à simplement pour but de tester le bon fonctionnement du timer. Il s'intègre dans un autre programme plus "complexe".

Pour la LED WS2812,c'était ma curiosité. Merci pour ta réponse 5_cylindres. Ca confirme ce que j'avais déjà lu sur d'autres topics.
Merci de la précision kamil, j'utilise actuellement cette librairie, donc si elle est compatible avec l'attiny84 cela m'arrange.

Et enfin pour répondre à ma problématique. Il s'avère que c'est simplement la routine d'interruption qui était mal orthographiée ( j'ai trouvé ca sur un topic anglophone).

C'est : ISR(TIM1_OVF_vect) et non pas ISR(TIMER1_OVF_vect)

Je vous remercie beaucoup pour votre aide.

Bonne soirée.

oups ! désolé ...
je viens de (re)consulter la doc du '84A' : j'avais complètement zappé cette orthographe particulière.
encore pardon d'avoir mal lu, mais le principal est que tu aies réussi.

passons à la suite : que vas-tu faire pour les DELs ? utiliser des WS2812 et la bibli Adafruit ? ou gérer des APA102 ? dans ce dernier cas, je peux t'aider ... mais je pense que tu peux même t'en sortir tout seul !