Problème PROGMEM

Bonjour
J'ai un problème de compilation lors de l'utilisation de PROGMEM pour un affichage sur écran type NOKIA 5110.
Voici le listing :

/* Affiche sur l'écran un image stockée en PROGMEM */
void lcd_image_flash(prog_uchar *data){
  for (int i = 0 ; i < (LCD_X * LCD_Y / 8) ; i++)
    lcd_write(LCD_DATA, pgm_read_byte_near(data +i));
}

et aussi :

void lcd_string_flash(prog_char *str) {
  char c = pgm_read_byte_near(str);
  while(c) {
    lcd_putChar(c);
    c = pgm_read_byte_near(++str);
  }
}

Pourtant, j'appelle bien

#include <avr/pgmspace.h>

Voici le message à la compilation :

In file included from C:\Users\irena\AppData\Local\Temp\arduino_build_307415\sketch\AVR_afficheur.cpp:3:0:

C:\Users\irena\AppData\Local\Temp\arduino_build_307415\sketch\AVR_afficheur.h:6:22: error: variable or field 'lcd_image_flash' declared void

 void lcd_image_flash(prog_uchar *data);

                      ^

C:\Users\irena\AppData\Local\Temp\arduino_build_307415\sketch\AVR_afficheur.h:6:22: error: 'prog_uchar' was not declared in this scope

C:\Users\irena\AppData\Local\Temp\arduino_build_307415\sketch\AVR_afficheur.h:6:34: error: 'data' was not declared in this scope

Quelqu'un peut-il m'expliquer ce qui ne va pas ? Je précise si nécessaire que je suis sur un nano.
Merci

prog_uchar n'est plus déclaré depuis quelques années (ID 1.5.7).
essayez en remplaçant le type par const unsigned char

avant: prog_uchar message[] PROGMEN = { "Salut" };
aujourd'hui: const unsigned char message[] PROGMEM = { "Salut" };

(ou refaites un typedef)

pepe:
Pour continuer à utiliser prog_uchar, il devrait suffire de déclarer la macro PROG_TYPES_COMPAT avant d'inclure avr/pgmspace.h :

#define __PROG_TYPES_COMPAT__

#include <avr/pgmspace.h>




Je n'ai pas essayé sous l'IDE 1.8.x, mais cela marchait encore sous l'IDE 1.7.11.

Merci, ça fonctionne. Mais la compil fait apparaître une autre erreur.
Je définis une table de codage de caractères ASCII comme suit dans un fichier .h :

// Table ascii des carateres, sur 5 pixels de large par 8 pixels de haut
prog_uchar asciiTable[] PROGMEM = {
   0x00, 0x00, 0x00, 0x00, 0x00 // 20  
  ,0x00, 0x00, 0x5f, 0x00, 0x00 // 21 !

...
};

Et le compilateur n'aime pas quelque chose :

In file included from C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Arduino.h:28:0,

                 from C:\Users\***\AppData\Local\Temp\arduino_build_307415\sketch\AVR_afficheur.cpp:3:

C:\Users\***\AppData\Local\Temp\arduino_build_307415\sketch\AVR_ascii_table.h:2:25: error: variable 'asciiTable' must be const in order to be put into read-only section by means of '__attribute__((progmem))'

 prog_uchar asciiTable[] PROGMEM = {

                         ^

exit status 1
Erreur de compilation pour la carte Arduino Nano

Qu'est ce qu'il se passe ? J'ai pourtant bien mis le #define PROG_TYPES_COMPAT avant la déclaration #include <avr/pgmspace.h>

comme mentionné plus haut essayez avec

const unsigned char asciiTable[] PROGMEM = {
   0x00, 0x00, 0x00, 0x00, 0x00 // 20  
  ,0x00, 0x00, 0x5f, 0x00, 0x00 // 21 !
...
};

(sans les ... bien sûr :slight_smile: )

Désolé, c'est réglé en le déclarant en "const unsigned"
Du coup d'autres erreurs apparaissent, toutes du même type :

In file included from C:\Users\***\AppData\Local\Temp\arduino_build_307415\sketch\AVR_afficheur_test.cpp:3:0:

C:\Users\***\AppData\Local\Temp\arduino_build_307415\sketch\AVR_afficheur.h:6:22: error: variable or field 'lcd_image_flash' declared void

 void lcd_image_flash(prog_uchar *data);

Voici le code correspondant :

/* Affiche sur l'écran un image stockée en PROGMEM */
void lcd_image_flash(prog_uchar *data){
  for (int i = 0 ; i < (LCD_X * LCD_Y / 8) ; i++)
    lcd_write(LCD_DATA, pgm_read_byte_near(data +i));
}

Comment régler ça aussi ? Je remplace "prog_uchar" par "unsigned char" ?

Essayez de remplacez partout prog_uchar par const unsigned char (faites une sauvegarde avant)

J-M-L:
Essayez de remplacez partout prog_uchar par const unsigned char (faites une sauvegarde avant)

Je débute en C, mais je suppose que je ne peux pas mettre des "const" dans des paramètres de fonctions ?

si si sans pb. Vous informez ainsi le compilateur que la fonction n'a pas le droit de modifier ce paramètre

s'il y a une étoile * qui suit, il faut la laisser cependant, ça veut dire "pointeur sur"

void lcd_image_flash(prog_uchar [color=red]*[/color]data){
devient

void lcd_image_flash(const unsigned char [color=red]*[/color]data){

C'est bon, ça marche. Merci à tous !!

Super :slight_smile:

Bonjour,

Le topic est ancien mais je bute sur les mêmes problèmes et je n'arrive pas à m'en dépetrer.
J'utilise un programme écrit par quelqu'un et je ne maitrise pas tout.
Je pense que j'ai réussi à corriger certins pbs en remplaçant PROGMEM prog_uchar toto [] = ... par char toto [] = ...

mais plus loin ça coince. en suivant ce topic j'ai remplacé les
prog_char m_Reglage_0[] PROGMEM = "ACCORD"; par const unsigned char m_Reglage_0[] PROGMEM = "ACCORD";
par contre après, je remplace
const char *menu_Reglage[] PROGMEM = {... par const unsigned char *menu_Reglage[] PROGMEM = {...

mais j'ai l'erreur suivante
error: variable 'menu_Reglage' must be const in order to be put into read-only section by means of 'attribute((progmem))'

et pour moi, ce n'est ni du C ni de l'anglais mais du martien ... :frowning:

J-M-L, si tu es encore sur le sujet, pourrais-tu m'aider stp ?
Je ne sais pas si c'est très clair mais je ne peux pas mettre tout le code.
merci d'avance.

menu_Reglage est bien un tableau de pointeurs? Avec quoi est-il initialisé?

J'ai l'impression que l'on peut mettre des tableaux d'entiers, de char.... mais pas de pointeurs.

merci pour ta réponse rapide.
Alors je ne sais pas ce que j'ai fait mais ça compile. Je ne peux juste pas encore tester pour le moment car je n'ai pas reçu tout le matériel.
J'ai fait les modifs suivantes :
j'ai remplacé les
PROGMEM prog_uchar Sinus[] = {...
par
PROGMEM const char Sinus[] = {...

ensuite j'ai remplacé les
PROGMEM prog_int16_t Onde_Hz[] = {...
par
PROGMEM const int16_t Onde_Hz[] = {...

j'ai remplacé les
prog_char m_Reglage_0[] PROGMEM = "ACCORD";
par
PROGMEM const char m_Reglage_0[] = "ACCORD";

j'ai enfin remplacé les
const char *menu_Reglage[] PROGMEM = { m_Reglage_0, ...
par
const char menu_Reglage[] = { m_Reglage_0, ...

et tout ça compile et link OK. Je verrai si ça marche comme prévu, mais peux-tu me dire stp si déjà c'est cohérent et a un sens ?
j'ai cru comprendre que la directive PROGMEM indiquait au compilateur que la donnée est une constante à ranger en flash et ensuite le tableau de chaine vient chercher les valeurs dans cette zone. C'est bien ça ?

merci en tous cas de ton support. Si c'est OK, je viendrai le confirmer ici pour indiquer la résolution.

Postez le code sinon on parle plutôt dans le vide

PROGMEM est une directive de compilation qui dit de stocker l’information en mémoire flash on peut y mettre ce qu’on veut en faisant attention à comment on écrit cela et ensuite il faut utiliser des fonctions spéciales pour aller lire le contenu

On peut y mettre ce que l'on veut à condition que ce soit des constantes. Je suppose que l'on doit pouvoir changer la valeur, mais cela doit être beaucoup plus compliqué.

changer:
const char *menu_Reglage[]
en:
const char menu_Reglage[]
ne doit pas du tout faire la même chose...

Il y a un truc que je ne comprendrai jamais, c'est pourquoi les gens ne vont jamais lire la doc avant de poser des questions.
Tout est là: la déclaration de chaînes avec PROGMEM, la déclaration de tableaux de chaînes avec PROGMEM.
Il est dit aussi qu'il est préférable de placer le mot clé PROGMEM après le nom de la variable pour des raisons de compatibilité avec des anciennes versions du compilateur. En tout cas pas en tête de la déclaration.

Après, si la doc n'est pas claire que l'on vienne poser des questions ne me pose pas de problème

Ça me semblait évident pour tous qu’on parlait de constantes ...

Merci de vos retours rapides et votre aide.
Voici le code d'origine.
https://drive.google.com/drive/folders/1oXrtlf_3Sg96nq4wOSn7arhRB78Hc3ch?usp=sharing
je ne mets pas le code par la balise code car il est assez gros mais j'espère que le lien est OK.

Merci

Il y a un truc que je ne comprendrai jamais, c'est pourquoi les gens ne vont jamais lire la doc avant de poser des questions.

Je ne me permets pas de répondre pou les autres, mais je peux répondre pour moi.

  • si la doc état en français il n'y aurait pas tant de problèmes.
  • si la doc était en espagnol, cela me serait plus facile.
  • je n'ai rien contre l'anglais, même si j'ai redoublé uniquement à cause de l'anglais (note éliminatoire à un concours)
  • souvent j'ai un problème pour trouver la doc
  • la doc est faite par celui qui a écrit le code, c'est donc souvent une personne avec des compétences supérieures à celui à qui il s'adresse, et la pédagogie n'est pas forcément présente.
  • si il y a ue tant de discussions à propos des VGS des mosfets ces derniers temps, alors qu'il est très facile de trouver la doc, c'est un problème d'interprétation.
  • la doc n'existe pas bien souvent, et si on pouvait compter systématiquement dessus, on y aurait certainement recours plus souvent.
  • en traduisant la doc par google, j'ai eu une fois un "losrque la broche est à l'état bas" traduit par losrque la broche est à l'état haut"

Maintenant en lisant la doc de PROGMEM, je lis:

Parameters
dataType: Allowed data types: any variable type.

que je traduirais bêtement par :

Paramètres
dataType: Types de données autorisés: tout type de variable..

J'en conclurais que les tableaux de pointeurs sont autorisés si les pointeurs sont constants.

Parler l'anglais pour faire de l'informatique est identique à savoir faire de la mécanique pour conduire une voiture (au passage pour ceux qui ont une voiture: qui a lu la notice d'utilisation avant de la conduire?).

On stocke en PROGMEM des suite de octets. La façon dont vous les interpréter ensuite est à votre choix. Comme c’est décidé à la compilation, il faut bien entendu que ces valeurs soient connues à ce moment là

Pour l’anglais je n’ai jamais vu Google traduire LOW par HAUT.... vraiment surprenant. Ensuite ça reste de l’open source donc on peut soulever le capot et mettre les mais dans le cambouis si on veut explorer plus.

Tenez voici un exemple qui illustre comment on traitre des pointeurs, une structure etc

#include <avr/pgmspace.h>

enum situation_t : uint8_t {single, couple, RIP};

// on met 3 cSrting en PROGMEM qui correspondent à la situation
const char s0[] PROGMEM = "single";
const char s1[] PROGMEM = "couple";
const char s2[] PROGMEM = "rest in peace";

// on met l'adresse de ces cStrings en PROGMEM
const char* const descriptionSituation[] PROGMEM = {s0, s1, s2};

// on définit une structure dont le prénom est un pointeur constant
struct person_t {
  const char * firstName;
  const uint8_t d;
  const uint8_t m;
  const uint16_t y;
  situation_t situation;
};


// On définit des cString en PROGMEM pour les prénoms
const char auguste[] PROGMEM = "Auguste";
const char camille[] PROGMEM = "Camille";
const char victor[] PROGMEM = "Victor";
const char juliette[] PROGMEM = "Juliette";
const char someone[] PROGMEM = "Mr Unknown";

// on met toute la structure en PROGMEM, dont le pointeur sur le prénom
const person_t population[] PROGMEM =
{
  {auguste, 12, 11, 1840, RIP}, 
  {camille, 8, 12, 1864, RIP},
  {victor, 26, 2, 1802, RIP},
  {juliette, 10, 4, 1806, RIP},
  {someone, 1, 1, 2000, single}
};

// on peut calculer à la compilation le nombre d'éléments comme d'habitude
const uint16_t nbElements = sizeof(population) / sizeof(population[0]);


void setup() {
  Serial.begin(115200);
  for (const auto& member : population) // on va parcourir le tableau
  {
    Serial.println((const __FlashStringHelper *) pgm_read_word(&(member.firstName))); // on va chercher le pointeur et on cast pour que print commprenne que c'est en flash
    Serial.print  (pgm_read_byte_near(&(member.d)) ); // cast optionnel ici car pgm_read_byte_near va déjà retourner un uint8_t
    Serial.write("/");
    Serial.print  (pgm_read_byte_near(&(member.m)) ); // cast optionnel ici car pgm_read_byte_near va déjà retourner un uint8_t
    Serial.write("/");
    Serial.println((uint16_t) pgm_read_word_near(&(member.y)) ); // cast optionnel ici car pgm_read_word_near va déjà retourner un uint16_t
    Serial.println((const __FlashStringHelper *) pgm_read_word(&(descriptionSituation[(uint8_t) pgm_read_byte_near(&(member.situation))])));
    Serial.println(F("------------------------------"));
  }
}

void loop() {}

le moniteur série (à 115200 bauds) affichera

[color=purple]
Auguste
12/11/1840
rest in peace
------------------------------
Camille
8/12/1864
rest in peace
------------------------------
Victor
26/2/1802
rest in peace
------------------------------
Juliette
10/4/1806
rest in peace
------------------------------
Mr Unknown
1/1/2000
single
------------------------------

[/color]