ATtiny 84 : augmenter la résolution du PWM

Bonjour à tous,
je me tourne vers vous car je cherche à augmenter la résolution PWM d'un ATtiny84.
Voici ma source d'inspiration :
http://www.technoblogy.com/show?1NGL
Ici il s'agit d'un attiny85, je souhaiterais faire la même chose avec un ATtiny84, sur la sortie PA7.
Je ne suis pas du tout familier avec l'écriture sur les registres et pour l'instant mes essais sont infructueux, je n'arrive même pas à générer un PWM 8 bit...

bouault:
Bonjour à tous,
je me tourne vers vous car je cherche à augmenter la résolution PWM d'un ATtiny84.
Voici ma source d'inspiration :
Technoblogy - 10 or 12-bit DAC from the ATtiny85
Ici il s'agit d'un attiny85, je souhaiterais faire la même chose avec un ATtiny84, sur la sortie PA7.
Je ne suis pas du tout familier avec l'écriture sur les registres et pour l'instant mes essais sont infructueux, je n'arrive même pas à générer un PWM 8 bit...

Bonjour jacques
qu'est que tu entend là exactement par résolution ?
un signal PWM c'est surtout caractérisé par la fréquence de récurrence (qui découle de l'horloge MCU) et le duty cycle
a tout hasard
regarde çà

Hello Artouste,
Par résolution, je veux dire le nombre de pas. En 8 bits 255 pas, 1023 en 10 bits, 4095 en 12 bits.
Je parle bien du le duty cycle.

Par simple curiosité quelle est l'utilité d'avoir 4095 pas ? Cela fait une précision de 0,025% .

C'est simple :
avec une LED puissante, en 8 bits, au pas 1/255 la LED éclaire déjà fortement. En 12 bits, avec en plus une courbe, c'est déjà bien meilleur. Je dit meilleur car ce n'est encore pas parfait.
Pourquoi une telle exigence ? Parce que je suis éclairagiste de théâtre...

Ok.
En fait l'idéal serait de commander la diode non pas en "simili courant" comme actuellement mais avec une vraie source de courant variant entre 0A- Imax.
La résistance que l'on met en série avec la diode c'est pour fabriquer une pseudo source de courant constant.
La PWM ne faisant que hacher ce pseudo courant constant.

Evidement le réglage doit être continu et sans trous, on ne peux pas envisager de commuter des résistances en série avec la diode.

Exactement !
On peut faire ça avec un composant comme le LDD meanWell, il se pilote avec un PWM à une fréquence comprise entre 100 et 1000Hz

Voici le bon lien, pardon :

As tu regarder le site de Mike Gammon

Il contient énormément d'astuces et d'utilisation des registres..

J'ai aussi dans mes réserves (soigneusement oubliée) une note d'Application atmel :
AVR121: Enhancing ADC resolution by oversampling
C'est pour passer en 12 bits sur le convertisseur analogique digital mais peut-être il y a des idées à prendre.

Pour la PWM avec les registres je l'ai fait une fois pour voir.
Il faut être méthodique dans l'application de la datasheet et ne pas dédaigner le crayon pour annoter la datasheet.
Point remarquable : avec les registres quand on change le rapport cyclique le signal est propre instantanément, avec analogWrite() le signal est instable pendant plusieurs période de PWM.

je souhaiterais faire la même chose avec un ATtiny84, sur la sortie PA7.

Il y a quelque chose qui me choque: l'ATtiny84 possède deux compteurs qui permettent de faire du PWM:
le premier Timer0 est en 8 bits et sort notamment sur la broche PA7
le deuxième Timer1 qui est en 16 bits mais qui doit sortie en PA5

Si on veut un PWM de 16 bits pourquoi ne pas utiliser le deuxième?

Réponse à 68tjs :
merci, je regarde ces liens dans la journée.
Je ne suis pas surpris que la PWM ''avec registre" soit d'entrée plus propre, il semble qu'avec analogWrite(), on initialise à chaque appel à la fonction. Bon à savoir...

Réponse à Vileroi :
Oui en effet !
Le problème est que 5 I/O sont déjà occupées par un module radio RFM12B : PB0-PB2-PA6-PA5-PA4.
Pour info, je travaille sur cette carte : wilulu
sources Fritzing

Il reste peut-être la solution d'utiliser le timer 0 ou 1 qui déclenche une interruption 1000 fois trop rapide et de compter dans un programme d’interruption...
Si le beurre (PA5) et l'argent du beurre (PA6) sont déjà pris, le timer 1 est toujours disponible mais au travers des fonctions d'interruptions...
Encore faut-il savoir quelles sont les ressources encore disponibles

utiliser un timer pour déclencher une interruption c'est un peu l'idée développé dans le lien que j'avais mis en PJ au début, non ? (Technoblogy - 10 or 12-bit DAC from the ATtiny85)
Mon problème :Je n'arrive pas à l'adapter à l'ATtiny 84...
Qu'est-ce que tu entend par "quelle sont les ressources disponibles" ?

utiliser un timer pour déclencher une interruption c'est un peu l'idée développé dans le lien que j'avais mis en PJ au début, non ? (Technoblogy - 10 or 12-bit DAC from the ATtiny85)
Mon problème :Je n'arrive pas à l'adapter à l'ATtiny 84...

Effectivement, tant de choses sont passées... (et d'autes messages)

Je ne suis pas sûr de pouvoir débugger l'essai que tu as fait, mais je suis sûr que si on n'a pas le code, personne ne peut t'aider.

Je sais que sur une UNO un timer est occupé pour compter les millis() et les micros(). Il n'est pas impossible qu'un timer soit utilisé à cette fin sur la Wilulu par le module radio. Auquel cas l'utiliser l’empêcherait de fonctionner. De même que connaître les pins utilisées, si on en a besoin d'une, il faut savoir quel(s) timer est libre.

Voici mon code :

volatile int Dac = 0;
volatile int Cycle = 0;

// Overflow interrupt
ISR (TIMER0_OVF_vect) 
{
  static int remain;
  if (Cycle == 0) 
    remain = Dac;
  
  if (remain >= 256) 
  { 
    OCR0A=255; 
    remain = remain - 256; 
  }
  
  else 
    {
      OCR0A = remain;
      remain = 0;
    }
  Cycle = (Cycle + 1) & 0x03;

}

void analogWrite10 (int value) {
  cli(); Dac = value; sei();
}

void setup() {

  TCCR0A = _BV(COM0A1) | _BV(WGM00);
  TCCR0B = _BV(CS00) | _BV(WGM02);

  TIMSK0 = _BV(TOIE0);
  pinMode(7, OUTPUT);
}

void loop () {
  int value = 1000;
  analogWrite10(value);
  //analogWrite(WiluluOUT,255);
  delay(100);
}

il compile mais ne fonctionne pas...
La radio utilise le timer 1.

edit, je viens de jeter un oeil sur le code que tu as poster, il y a ce prob
analogWrite10(value);
il faut
analogWrite(10,value);
re edit: excuses moi, j'ai regardé trop vite

hello, veux tu tester ce code

#define sortie_signal_toggle digitalWrite (sortie_signal, !digitalRead(sortie_signal))
boolean isr_ext             = false;
long  compteur_ext          =     0;
long  compt_ext             =   500; //
long  seuil_pause_signal    =     0;
long  seuil_pulse_signal    =     0;
const byte sortie_signal    =    22; // sur cette sortie, tu auras un signal carré
                                     //tant que le boolean ISR sera à true
void setup() {
  pinMode(sortie_signal,OUTPUT);
TCCR1A = 0b00000010; // mode CTC  
TCCR1B = 0b00000001; // prescaler pas    
//TCCR1B = 0b00000010; // prescaler /8  
//TCCR1B = 0b00000011; // prescaler /64  
TIMSK1 = 0b00000010;   // égalité prise en compte 
OCR1A  = 250;          // de 0 à 250, voir les commentaires plus bas
  init_seuils();
  sei();
  isr_ext=true;
}
void loop() 
{
  //ici, tu peux lire un potentiometre
  //et avec une fonction map()et fais varier la valeur de
  //           seuil_pause_signal=map(analogRead,pot,0,1023,0,10000);
  //ou / et de seuil_pulse_signal=map(analogRead,pot,0,1023,0,10000);
  }
void init_seuils()
{ 
  seuil_pause_signal    = 10000;//si tu ne mets pas de potar, changes les valeurs ici
  seuil_pulse_signal    = 10000;
}
//OCR2A = 250 et prescaler /8
// 5 et 5 donnent 660HZ pour une periode de 1.5ms
//1000 et 1000 donnent 4Hz pour une periode de 250ms
//10000 et 10000 donnent 0.4Hz pour une periode de2.5s
//OCR2A = 10
//10 et 10 donnent 4000HZ periode de 231µs
//100 et 100 donnent 500Hz periode de 2ms
//500 et 500 donnent 100Hz periode de 10ms
//1000 et 1000 donnent 50 Hz periode de 20ms
//10000 et 10000 donnent 5 Hz periode de 200ms
ISR (TIMER1_COMPA_vect) 
//ISR (TIMER5_COMPA_vect) //origine
{
  if (isr_ext)
  {
    if (compteur_ext++ >= compt_ext )
    {
      sortie_signal_toggle; compteur_ext = 0;
      if (compt_ext == seuil_pulse_signal)
      {
        compt_ext = seuil_pause_signal;
      }
      else
      { 
        compt_ext = seuil_pulse_signal;
      }
    }
  }
}

Je ne crois pas, voici la fonction analogWrite10() :

void analogWrite10 (int value) 
{
  cli();
  Dac = value; 
  sei();
}

J'ai uplodé ton code tel quel, pour l'instant ça ne fonctionne pas, mais je ne désespères pas, il faut que je le lise bien pour le comprendre !
Merci en tout cas.

On est bien d'accord que :

 seuil_pause_signal    = 10000;
  seuil_pulse_signal    = 10000;

Devrait allumer la led au max ?

ces valeurs sont restées dans le code car j'ai testé plusieurs valeurs et j'ai noté les résultats sous forme de commentaire.

je pense que tu devras regler TCCR1B sur "pas de prescaler"
et jouer sur OCR1A et les valeurs des deux seuils pour avoir les fréquences que tu désires
mais oui, puisque la période obtenue est très longue, elle doit clignoter très lentement
le signal est observable sur la pin 22 d'une méga ( c'est ce que j'avais sous la main)
mais tu peux mettre une autre pin de sortie.

je viens de tester sur une UNO pin 8