[RESOLU] Led dimming:: Optimisation possible ?

Yep!

Alors je dois m'y prendre comme un pied car je tourne en rond depuis ce week-end.
Le cycle est relativement simple, binaire, mais comme tout ce qui est simple, je le complique...

Il s'agit d'une séquence binaire d'allumage/extinction de leds avec un peu de dimming afin d'anticiper le cycle suivant.

Ce qui m'énerve énormement, c'est de taper de nombreuses lignes de code identique.

J'ai pensé à créer une classe, une fonction dynamique, cependant mes connaissances du c++ sont presques au bout ou à bout.
Je sens que je passe à côté d'une solution simple et évidente. Peut-être que vous la verrez avant moi ???

/*
ATTiny2313

OC0A  PB2
OC1A  PB3
OC1B  PB4

### PINS CONFIGURATION ###

DDRB

*/
#include <avr/io.h>
#include <util/delay.h>
//#include <avr/pgmspace.h>

#define _wait 500
#define _ms 50
#define _sleep 5000
#define dim 50

byte redVal = 0;
byte greenVal = 0;
byte blueVal = 0;
boolean _init = true;

void setup()
{

  TCCR0A = 0x81;
  TCCR1A = 0xA1;
  TCCR1B = 0x3;
  
  DDRB = B00011100;
  __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");
  
}

void loop() 
{
  if(_init)
  {
    for(byte i = 0; i < dim; i++)
    {
      fade(i, 0, 0);
    }
    _init = false;
  }
  else
  {
  // ##################### 100 #####################
    for(byte i = dim; i < 255; i++)
    {
      fade(i, 0, 0);
    }
  
    _delay_ms(_sleep);
  
    for(byte i = 255; i > dim; i--)
    {
      fade(i, 0, 0);
    }
    
    for(byte i = dim; i > 0; i--)
    {
      fade(i, (dim-i), 0); _delay_ms(_ms);
    }
    // ##################### 010 #####################
    for(byte i = dim; i < 255; i++)
    {
      fade(0, i, 0);
    }
  
    _delay_ms(_sleep);
  
    for(byte i = 255; i > dim; i--)
    {
      fade(0, i, 0);
    }
    for(byte i = dim; i > 0; i--)
    {
      fade(0, i, (dim-i)); _delay_ms(_ms);
    }
    // ##################### 001 #####################
    for(byte i = dim; i < 255; i++)
    {
      fade(0, 0, i);
    }
  
    _delay_ms(_sleep);
  
    for(byte i = 255; i > dim; i--)
    {
      fade(0, 0, i);
    }
    for(byte i = dim; i > 0; i--)
    {
      fade((dim-i), i, i); _delay_ms(_ms);
    }
    // ##################### 101 #####################
    for(byte i = dim; i < 255; i++)
    {
      fade(i, 0, i);
    }
  
    _delay_ms(_sleep);
  
    for(byte i = 255; i > dim; i--)
    {
      fade(i, 0, i);
    }
    for(byte i = dim; i > 0; i--)
    {
      fade(i, (dim-i), i); _delay_ms(_ms);
    }
    // ##################### 011 #####################
    for(byte i = dim; i < 255; i++)
    {
      fade(0, i, i);
    }
  
    _delay_ms(_sleep);
  
    for(byte i = 255; i > dim; i--)
    {
      fade(0, i, i);
    }
    for(byte i = dim; i > 0; i--)
    {
      fade((dim-i), i, i); _delay_ms(_ms);
    }
    // ##################### 110 #####################
    // ##################### 111 #####################
  }
  
}

void fade(byte redVal, byte greenVal, byte blueVal)
{
  OCR1A = redVal;
  OCR1B = greenVal;
  OCR0A = blueVal;
  
  delay(_wait);
}

/*
COMPUTATION
  100 {a}
^ 110 {b}
  ---
  010
  
  byte c = a ^ b;
  a & (1 << 3) ? i : 0; // test bit 3 from {a}
*/

Il y a une routine évidente, la difficulté est de placer les variables de la fonction fade() au bon endroit au bon moment à partir d'un cycle prédefini:

for(byte i = dim; i < 255; i++)
  {
    fade(0, i, 0);
  }
  
  _delay_ms(_sleep);
  
  for(byte i = 255; i > dim; i--)
  {
    fade(0, i, 0);
  }
  for(byte i = dim; i > 0; i--)
  {
    fade(0, i, (dim-i)); _delay_ms(_ms);
  }

Merci pour votre aide.

@+

Zoroastre.

Salut,

J'appellerai pas ça une réel "optimisation" mais bon ...

#include <avr/io.h>
#include <util/delay.h>

#define _WAIT 500
#define _MS 50
#define _SLEEP 5000
#define DIM 50

uint8_t i, z;

void setup()
{
  TCCR0A = 0x81;
  TCCR1A = 0xA1;
  TCCR1B = 0x3;

  DDRB = B00011100;

  for(i = 0; i < DIM; i++)
    fade(i, 0, 0);
}

void loop() 
{
  for(z = 0; z < 6; z++) {
    for(i = DIM; i < 255; i++)
      fade((z & 4) ? i : 0, (z & 2) ? i : 0, (z & 1) ? i : 0);

    _delay_ms(_SLEEP);

    for(i = 255; i > DIM; i--)
      fade((z & 4) ? i : 0, (z & 2) ? i : 0, (z & 1) ? i : 0);

    for(i = DIM; i > 0; i--) {
      switch(z) {
      case 1:
        fade((DIM - i), i, i); // 001
        break;
      case 2:
        fade(0, i, (DIM - i)); // 010
        break;
      case 3:
        fade((DIM - i), i, i); // 011
        break;
      case 4:
        fade(i, (DIM - i), 0); // 100
        break;
      case 5:
        fade(i, (DIM - i), i); // 101
        break;
      }
      _delay_ms(_MS);
    }
  }	
}

void fade(uint8_t r, uint8_t g, uint8_t b) {
  OCR1A = r;
  OCR1B = g;
  OCR0A = b;
  _delay_ms(_WAIT);
}

(Ps: tu as 3 define différents pour les delay ? Leur noms sont pas trés significatif ...)

Avant : 156 lignes, 1184 octets
Aprés : 63 lignes, 1056 octets (- 93 lignes, - 128 octets)

Yep!

Merci skywodd :wink:

Je teste au plus vite.

J'avais un souci avec les delais. Impossible de claquer _delay_ms() dans la fonction fade(). J'ai donc du passer par un classique delay(). L'arduino semble comme figé, perdu dans un delais interminable.
La manipulation des pwm doit faire capoter le timer. Pourtant, je n'utilise pas directement TCCRB0...

EDIT 1: Il subsiste quelques imperfections, certaines étapes ont des coupures franches. Mais ta vision différente du cycle est interessante. Merci XD

@+

Zoroastre.

zoroastre:
J'avais un souci avec les delais. Impossible de claquer _delay_ms() dans la fonction fade(). J'ai donc du passer par un classique delay(). L'arduino semble comme figé, perdu dans un delais interminable.
La manipulation des pwm doit faire capoter le timer. Pourtant, je n'utilise pas directement TCCRB0...

PWM = Timer
delay = Timer
delay + Timer = conflit

Je voulais te faire un commentaire justement sur le faite d'utiliser __delay_cycles() au lieu de __delay_ms() ... mais vu que la fonction a été modifié entre les différente version de avr-gcc, et vu que je savais pas si tu avais un version avec __builtin_avr_delay_cycles() ...

Yep!

/*
ATTiny2313

OC0A  PB2   --> Red
OC1A  PB3   --> Green
OC1B  PB4   --> Blue

### PINS CONFIGURATION ###

DDRB

### TODO ###
Improve timer (in conflict with pwm)

*/
#include <avr/io.h>
#include <util/delay.h>
//#include <avr/pgmspace.h>

#define Wait(T) _delay_ms(T)
#define dim 50

#define compA(k) ((cycle & (cycle + 1)) & (1 << k) ? 50 : i)
#define compB(k) ((cycle ^ (cycle + 1)) & (1 << k) ? (dim-i) : 0)

byte cycle = 0;

void setup()
{

  TCCR0A = 0x81;
  TCCR1A = 0xA1;
  TCCR1B = 0x3;
  
  DDRB = B00011100;
  __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");
  
}

void loop() 
{

  if(cycle == 0x0)
  {
    for(byte i = 0; i < dim; i++)
    {
      fade(0, 0, i);
    }
  }

  cycle += 1;
  
  for(byte i = dim; i < 255; i++)
  {
    fade((cycle & (1 << 2) ? i : 0), (cycle & (1 << 1) ? i : 0), (cycle & (1 << 0) ? i : 0));
  }
  Wait(2000);
  for(byte i = 255; i > dim; i--)
  {
    fade((cycle & (1 << 2) ? i : 0), (cycle & (1 << 1) ? i : 0), (cycle & (1 << 0) ? i : 0));
  }
  for(byte i = dim; i > 0; i--)
  {
    fade(((cycle & (1 << 2)) ? compA(2) : compB(2)), ((cycle & (1 << 1)) ? compA(1) : compB(1)), ((cycle & (1 << 0)) ? compA(0) : compB(0)));
  }
  
  if(cycle == 0x7)
  {
    cycle = 0x0;
  }
  
}
void fade(uint8_t r, uint8_t g, uint8_t b) {
  OCR1A = r;
  OCR1B = g;
  OCR0A = b;
  Wait(50);
}

878 bytes

C'est un peu enorme à mon goût pour si peu de chose, mon bon, au moins le code a le mérite d'être un peu plus compacte.
(Il y a encore 2/3 trucs à modif et il sera parfait)

Encore merci :wink:

@+

Zoroastre.

Yop yop,
L'approche ternaire de sky est bonne (je pense pas qu'il y ai moyen de faire mieux).

La liaison entre les différentes séquences sont pas évidente, 100, 010, 001 après 101, 011, 110, 111 ?
Donc je suis passé à un tableau afin d'enregistré des séquence de valeurs différentes sans suite logique.
Il y a aussi la troisième boucle qui est une suite de la deuxième 255->DIM/DIM->0 donc qui peux être supprimer juste une condition pour le passage sous DIM ?

#include <avr/io.h>
#include <util/delay.h>

#define _WAIT 500
#define _MS 50
#define _SLEEP 5000
#define DIM 50

uint8_t i, z;
uint8_t seq[] = {4,2,1,5,3,6,7};

void setup()
{
  TCCR0A = 0x81;
  TCCR1A = 0xA1;
  TCCR1B = 0x3;

  DDRB = B00011100;

  for(i = 0; i < DIM; i++)
  {
    fade(i, 0, 0);
  }
}

void loop() 
{
  for(z = 0; z <= 6; z++) 
  {
    for(i = DIM; i < 255; i++)
    {
      fade((seq[z] & 4) ? i : 0, (seq[z] & 2) ? i : 0, (seq[z] & 1) ? i : 0);
    }
      

    _delay_ms(_SLEEP);

    for(i = 255; i > DIM; i--)
    {
      if(i > DIM)
      {
        fade((seq[z] & 4) ? i : 0, (seq[z] & 2) ? i : 0, (seq[z] & 1) ? i : 0);
      }
      else
      {
        switch(z) 
        {
          case 0:
            fade(i, (DIM-i), 0); // 100
            break;
          case 1:
            fade(0, i, (DIM-i)); // 010
            break;
          case 2:
            fade((DIM - i), i, i); // 001
            break;
          case 3:
            fade(i, (DIM-i), i); // 101
            break;
          case 4:
            fade(i, (DIM - i), i); // 011
            break;
          case 5:
            fade((DIM-i), i, i); // 110 ???
            break;
          case 6:
            fade((DIM-i), i, i); // 111 ???
            break;    
        }
        _delay_ms(_MS);
      }
    }
  }	
}

void fade(uint8_t r, uint8_t g, uint8_t b) {
  OCR1A = r;
  OCR1B = g;
  OCR0A = b;
  _delay_ms(_WAIT);
}

578 byte (pour ATTiny2313 8Mhz je n’obtiens pas les même valeurs que vous à la compil, version du core différent ?)

Yep!

578 byte (pour ATTiny2313 8Mhz je n’obtiens pas les même valeurs que vous à la compil, version du core différent ?)

J'obtiens les mêmes valeurs.

La liaison entre les différentes séquences sont pas évidente, 100, 010, 001 après 101, 011, 110, 111 ?

La séquence n'est pas figée en soi, elle est sur trois bits. J'ai commencé à l'envers,, c'est mon côté british dirons nous XD

Aprés un petit test rapide, car là il est 00h15, même défaut que skywodd, certaines sequences sont correctes, d'autres radicalement violentes au niveau des transitions.

La variable dim sert de repère pour le moment bascule entre le cycle en cours et le cycle suivant. Cette variable sera peut être ajustée sur le montage final.

Sur mon dernier code, j'ai défini 2 #define :

#define compA(k) ((cycle & (cycle + 1)) & (1 << k) ? 50 : i)
#define compB(k) ((cycle + 1) & (1 << k) ? (dim-i) : 0)

Si le bit est actif, on test compA() pour connaitre l'etat du bit du cycle suivant, si il est à 1, on bloque la valeur pwm à 50, sinon on suit i (decremente).
Si le bit est inactif, on test compB pour connaitre l'etat du bit suivant, si il est à 1, on démarre la led en question (dim-i), autrement elle est et sera à 0.
La demarche est gourmande mais elle fonctionne, je la mets dans ma besace.

Les transistions doivent être fluides et le séquencement aléatoire au possible. L'idée du tableau me plait bien, je n'ai pas encore réussi à l'appliquer correctement, du moins dans mes precedents essais.

L'approche ternaire de sky est bonne

J'avais l'esquisse en tête mais j'ai pris la problèmatique de travers, comme un manche quoi !!!
Je cherchais à faire une ou plusieurs fonctions alors que je sentais parfaitement que cela était inutile. Le brouillard !!!
Et skywodd m'a montré le chemin de la lumière XD

En tout cas, je ne manquerais pas de jeter un regard attentif sur ton code et te remercie vivement :wink:

Sur ce, je vais me coucher :sleeping: :sleeping: :sleeping:

@+

Zoroastre.

Yep!

Osaka, j'ai regardé ton code et compris pourquoi il était si léger XD

Petite erreur ici :

...
for(i = 255; i > DIM; i--)
    {
      if(i > DIM)
...

578 bytes

...
for(i = 255; i > 0; i--)
    {
      if(i > DIM)
...

876 bytes

+300 bytes en modifiant juste un caractère XD XD (-->petits effets, grandes conséquences)

Pour ma part, en reprenant les élements que vous m'avez apportez, je suis descendu à 816 764 bytes.
Comme je suis fougueux et témeraire, je vise sous la barre des 800 700 noooowww !!!
(Avec comme impératifs :: cycle, variable dim et timer modifiables.)

Encore merci les gars :wink:

@+

Zoroastre.

zoroastre:
Yep!

Petite erreur ici :
...

+300 bytes en modifiant juste un caractère XD XD (-->petits effets, grandes conséquences)

:grin: Je me disais bien qu'il y avait quelque chose de bizarre. :stuck_out_tongue_closed_eyes: :*
N’empêche c'est le genre de chose que je n'aurais pas vu et même pas pensé avant la compil pour microcontrôleurs.

zoroastre:
Comme je suis fougueux et témeraire, je vise sous la barre des 800 700 noooowww !!!

J'ai la solution. :grin:

...
for(i = 255; i > 254; i--)
    {
      if(i > DIM)
...

Sinon juste pour expérience j'ai essayé vite fais une approche sans boucle, juste profité de "l’inertie" de loop.
Résultat 874octet, contre 876octet pour le précédent avec for (corrigé :grin:), donc aucun gain (à part qu'il n'y a aucun code bloquant) mais intéressent pour mon expérience personnel. :open_mouth:

#include <avr/io.h>
#include <util/delay.h>

#define _WAIT 500
#define _MS 50
#define _SLEEP 5000
#define DIM 50

uint8_t i, z;
uint8_t seq[] = {4,2,1,5,3,6,7};
uint8_t inc = 1;
void setup()
{
  TCCR0A = 0x81;
  TCCR1A = 0xA1;
  TCCR1B = 0x3;

  DDRB = B00011100;

}

void loop() 
{
  if(z <= 6) 
  {    
    if(i < DIM)
    {
      if(inc)
      {
        fade(i, 0, 0);
      }
      else
      {
        switch(z) 
        {
          case 0:
            fade(i, (DIM-i), 0); // 100
            break;
          case 1:
            fade(0, i, (DIM-i)); // 010
            break;
          case 2:
            fade((DIM - i), i, i); // 001
            break;
          case 3:
            fade(i, (DIM-i), i); // 101
            break;
          case 4:
            fade(i, (DIM - i), i); // 011
            break;
          case 5:
            fade((DIM-i), i, i); // 110 ???
            break;
          case 6:
            fade((DIM-i), i, i); // 111 ???
            break;    
        }
        _delay_ms(_MS); 
      }
    }
    else
    {
      fade((seq[z] & 4) ? i : 0, (seq[z] & 2) ? i : 0, (seq[z] & 1) ? i : 0);
    }
  }
  else
  {
    z = 0;
  }
  
  if(inc)
  {
    ++i;
    if(i == 255)
    {
      inc = 0;
      _delay_ms(_SLEEP);
    }
  }
  else
  {
    --i;
    if(!i)
    {
      inc = 1;
      ++z;
    }
  }
}

void fade(uint8_t r, uint8_t g, uint8_t b) 
{
  OCR1A = r;
  OCR1B = g;
  OCR0A = b;
  _delay_ms(_WAIT);
}

Bon vu que c'est parti pour tout optimiser et gratter un maximum d'octets ...

Optimisations possible :

  • Avr-gcc + makefile + optimisations gcc au max
  • inline assembly
  • fonction main en attribut "naked"

Enfin bon aprés on pourrait faire des optimisations encore plus poussé mais là ça irait un peu loin :roll_eyes: