Salvataggio Array in SRAM - LCD BigFont

Salve, chiedo venia per la mia scarsa preparazione in materia ma mi sono trovato di fronte ad un nuovo problema e necessito di un aiutino per oltrepassare lo scoglio incontrato....

All'interno del mio programma io creo due set di caratteri speciali da inviare ad un LCD 4x40... un set mi consente di scrivere delle lettere, mentre l'altro mi consente di scrivere dei numeri e all'occorrenza direttamente dal software carico con lcd.createChar il set che mi occorre...

Il tutto risultava funzionante, ma come ho già scritto (E risolto in parte) in un altro post mi occorre maggior memoria RAM libera altrimenti il tutto si blocca.

Uno dei consigli (e ringrazio Leo72 per questo) è stato quello di caricare i font direttamente in flash con PROGMEM e qui si complica il tutto... ho letto i vari reference ed esempi sull'utilizzo di questa funzione ma mi da sempre degli errori...

Di seguito allego il codice prima della modifica.... dopo la modifica... e l'errore che mi sta dando... se qualche anima pia mi potesse dire come risolvere, o cmq cosa stà dando fastidio al compilatore... gliene sarei grato in eterno.....

byte a1[8] = // array to make an arrow pointing up
{
	B00000,
	B11111,
	B11111,
	B11111,
	B11111,
	B11111,
	B00000,
	B00000

};
byte a2[8] = // array to make an arrow pointing up
{
	B00000,
	B11100,
	B11110,
	B11111,
	B11111,
	B11111,
	B11111,
	B11111

};
byte a3[8] = // array to make an arrow pointing up
{
	B11111,
	B11111,
	B11111,
	B11111,
	B11111,
	B11111,
	B01111,
	B00111

};
byte a4[8] = // array to make an arrow pointing up
{
	B00000,
	B00000,
	B00000,
	B11111,
	B11111,
	B11111,
	B11111,
	B11111

};
byte a5[8] = // array to make an arrow pointing up
{
	B11100,
	B11110,
	B11111,
	B11111,
	B11111,
	B11111,
	B11111,
	B11111

};
byte a6[8] = // array to make an arrow pointing up
{
	B11111,
	B11111,
	B11111,
	B11111,
	B11111,
	B11111,
	B00000,
	B00000

};
byte a7[8] = // array to make an arrow pointing up
{
	B11111,
	B11111,
	B11111,
	B11111,
	B11111,
	B00000,
	B00000,
	B00000

};
byte a8[8] = // array to make an arrow pointing up
{
	B11000,
	B01100,
	B00110,
	B11111,
	B11111,
	B00110,
	B01100,
	B11000

};
byte b1[8] = // array to make an arrow pointing up
{
	B00111,
	B01111,
	B11111,
	B11111,
	B11111,
	B11111,
	B11111,
	B11111

};
byte b2[8] = // array to make an arrow pointing up
{
	B11111,
	B11111,
	B00011,
	B00011,
	B00011,
	B00011,
	B11111,
	B11111

};
byte b3[8] = // array to make an arrow pointing up
{
	B11100,
	B11110,
	B11111,
	B11111,
	B11111,
	B11111,
	B11111,
	B11111

};
byte b4[8] = // array to make an arrow pointing up
{
	B11111,
	B11111,
	B11111,
	B11111,
	B11111,
	B11111,
	B01111,
	B00111

};
byte b5[8] = // array to make an arrow pointing up
{
        B00000,
	B00000,
	B11111,
	B11111,
	B11111,
	B00000,
	B00000,
	B00000
};
byte b6[8] = // array to make an arrow pointing up
{
	B11111,
	B11111,
	B11111,
	B00000,
	B00000,
	B00000,
	B00000,
	B00000

};
byte b7[8] = // array to make an arrow pointing up
{
	B11111,
	B11111,
	B11111,
	B11111,
	B11111,
	B11111,
	B11110,
	B11100

};

byte b8[8] = // array to make an arrow pointing up
{
	B00000,
	B00000,
	B00000,
	B00000,
	B00000,
	B11111,
	B11111,
	B11111

};

Questo era il codice dei due set di caratteri.... ogni array è stato modificato come segue....

PROGMEM const byte a1[8] = // array to make an arrow pointing up
{
	B00000,
	B11111,
	B11111,
	B11111,
	B11111,
	B11111,
	B00000,
	B00000

};
PROGMEM const byte a2[8] = // array to make an arrow pointing up
{
	B00000,
	B11100,
	B11110,
	B11111,
	B11111,
	B11111,
	B11111,
	B11111

};
PROGMEM const byte a3[8] = // array to make an arrow pointing up
{
	B11111,
	B11111,
	B11111,
	B11111,
	B11111,
	B11111,
	B01111,
	B00111

};
PROGMEM const byte a4[8] = // array to make an arrow pointing up
{
	B00000,
	B00000,
	B00000,
	B11111,
	B11111,
	B11111,
	B11111,
	B11111

};
PROGMEM const byte a5[8] = // array to make an arrow pointing up
{
	B11100,
	B11110,
	B11111,
	B11111,
	B11111,
	B11111,
	B11111,
	B11111

};
PROGMEM const byte a6[8] = // array to make an arrow pointing up
{
	B11111,
	B11111,
	B11111,
	B11111,
	B11111,
	B11111,
	B00000,
	B00000

};
PROGMEM const byte a7[8] = // array to make an arrow pointing up
{
	B11111,
	B11111,
	B11111,
	B11111,
	B11111,
	B00000,
	B00000,
	B00000

};
PROGMEM const byte a8[8] = // array to make an arrow pointing up
{
	B11000,
	B01100,
	B00110,
	B11111,
	B11111,
	B00110,
	B01100,
	B11000

};
PROGMEM const byte b1[8] = // array to make an arrow pointing up
{
	B00111,
	B01111,
	B11111,
	B11111,
	B11111,
	B11111,
	B11111,
	B11111

};
PROGMEM const byte b2[8] = // array to make an arrow pointing up
{
	B11111,
	B11111,
	B00011,
	B00011,
	B00011,
	B00011,
	B11111,
	B11111

};
PROGMEM const byte b3[8] = // array to make an arrow pointing up
{
	B11100,
	B11110,
	B11111,
	B11111,
	B11111,
	B11111,
	B11111,
	B11111

};
PROGMEM const byte b4[8] = // array to make an arrow pointing up
{
	B11111,
	B11111,
	B11111,
	B11111,
	B11111,
	B11111,
	B01111,
	B00111

};
PROGMEM const byte b5[8] = // array to make an arrow pointing up
{
        B00000,
	B00000,
	B11111,
	B11111,
	B11111,
	B00000,
	B00000,
	B00000
};
PROGMEM const byte b6[8] = // array to make an arrow pointing up
{
	B11111,
	B11111,
	B11111,
	B00000,
	B00000,
	B00000,
	B00000,
	B00000

};
PROGMEM const byte b7[8] = // array to make an arrow pointing up
{
	B11111,
	B11111,
	B11111,
	B11111,
	B11111,
	B11111,
	B11110,
	B11100

};

PROGMEM const byte b8[8] = // array to make an arrow pointing up
{
	B00000,
	B00000,
	B00000,
	B00000,
	B00000,
	B11111,
	B11111,
	B11111

};

A questo punto il compilatore mi stà dando errore nel momento in cui vado a definire i caratteri per l'cd e cioè in questa parte di codice :

void cambiacarattere(int flagcarattere) {
    if (flagcarattere == 1) {
      lcd.createChar(0, b1);
      lcd.createChar(1, b2);
      lcd.createChar(2, b3);
      lcd.createChar(3, b4);
      lcd.createChar(4, b5);
      lcd.createChar(5, b6);
      lcd.createChar(6, b7);
      lcd.createChar(7, b8);
  } else {    
          lcd.createChar(0, a1);
          lcd.createChar(1, a2);
          lcd.createChar(2, a3);
          lcd.createChar(3, a4);
          lcd.createChar(4, a5);
          lcd.createChar(5, a6);
          lcd.createChar(6, a7);
          lcd.createChar(7, a8);
  }
}

dandomi come errore:

error: invalid conversion from 'const byte*' to 'uint8_t*'
error: initializing argument 2 of 'void LiquidCrystal::createChar(uint8_t, uint8_t*)'

Scusate se mi sono dilungato ma ho voluto fornire quanti più dati possibili perchè qualcuno (Leo72 vedi di partecipare) mi volesse dare una mano.

Grazieeeeeeeee

Piccolo aggiornamento:

Provando a richiamare il contenuto della flash in questo modo:

lcd.createChar(0, pgm_read_byte(b1));

ottengo il seguente errore:

error: invalid conversion from 'uint8_t' to 'uint8_t*'
error: initializing argument 2 of 'void LiquidCrystal::createChar(uint8_t, uint8_t*)'

Chiedo LUMI !!!

Sembra un problema di conversioni fra tipi. Purtroppo non so che genere di dati tratta la libreria LCDcrystal. Però pare che chieda un puntatore (uint8_t*)mentre tu gli passi un oggetto byte (uint8_t). Non so se sia questo il problema.

esattamente quello che penso anche io, prova a togliere in const

Scusate.....cioè cosa dovrei modificare? togliere const nella dichiarazione PROGMEM ?

Esatto.
Se il compilatore accetta questa cosa, ricordati però di NON alterare in nessun modo quei dati.
Questo è un bel tutorial su PROGMEM

credo sia perchè definendolo come costante non gli permette di modificare il tipo dei dati.

detto questo prova, magari sbaglio io, è solo una teoria :wink:

Allora....

Togliendo tutti i const alla dichiarazioni dei caratteri speciali ottengo che:

lasciando

lcd.createChar(0, pgm_read_byte(b1));

ottengo sempre il solito errore:

error: invalid conversion from 'uint8_t' to 'uint8_t*'
error: initializing argument 2 of 'void LiquidCrystal::createChar(uint8_t, uint8_t*)'

mentre togliendo pgm_read_byte e lasciando la dichiarazione come se fosse una variabile normale... cioè:

      lcd.createChar(0, b1);

il compilatore compila senza errori ma LCD mostra caratteri strani e non quelli che io avrei dovuto salvare precedentemente....

Sono del tutto in alto mareeeeeeeee

pgm_read_byte(b1) non può ritornare un puntatore a tipo perchè il tipo non è in ram, la soluzione potrebbe essere di creare un puntatore in ram

uint8_t *dataChar;

dataChar = read_byte(b1);

e poi passi dataChar a createChar.

Questo funziona se il valore dataChar viene salvato nella ram del display, diversamente vedrai un solo carattere, l'ultimo passato.

Ciao.

Dalla pag. 4 di quel PDF che ho linkato analizzano proprio il problema delle costanti in Flash da passare a librerie di gestione di LCD.

Ho dato un'occhiata a quel pdf ma c'è no capito poco devo approfondire. Lo metto da parte per quando dovrò comandare un display. Comunque leggendo rapidamente si dice quello che ho detto io, però da la soluzione più elegante utilizzando delle macro fatte a posta per agirare il problema.

Ciao.

Fermo restando che ho provato a leggere il pdf ma non trovo affinità con la mia problematica (sicuramente per incompetenza mia) in quanto nel pdf stiamo parlando di una variabile che comunque viene richiamata per poterla scrivere... in modo "elegante" come è stato scritto qua sopra cioè attraverso macro, ma (come è giusto che sia) non si fa riferimento a caratteri speciali creati per lcd... e credo sia proprio questo il mio problema

Provando invece la soluzione di Maurotec ecco i risultati

uint8_t *bb1;
bb1 = pgm_read_byte(b1);
lcd.createChar(0, bb1);

L'errore che viene riportato sul secondo rigo è sempre lo stesso

error: invalid conversion from 'uint8_t' to 'uint8_t*'

Che forse non si possa fare? :roll_eyes:

Ciao,

cosi' compila

// Import libreria LiquidCrystal
#include <LiquidCrystal.h>

// Import libreria gestione memoria nella memoria programmi
#include <avr/pgmspace.h>

PROGMEM const byte a1[8] = // array to make an arrow pointing up
{
	B00000,
	B11111,
	B11111,
	B11111,
	B11111,
	B11111,
	B00000,
	B00000

};
PROGMEM const byte a2[8] = // array to make an arrow pointing up
{
	B00000,
	B11100,
	B11110,
	B11111,
	B11111,
	B11111,
	B11111,
	B11111

};
PROGMEM const byte a3[8] = // array to make an arrow pointing up
{
	B11111,
	B11111,
	B11111,
	B11111,
	B11111,
	B11111,
	B01111,
	B00111

};
PROGMEM const byte a4[8] = // array to make an arrow pointing up
{
	B00000,
	B00000,
	B00000,
	B11111,
	B11111,
	B11111,
	B11111,
	B11111

};
PROGMEM const byte a5[8] = // array to make an arrow pointing up
{
	B11100,
	B11110,
	B11111,
	B11111,
	B11111,
	B11111,
	B11111,
	B11111

};
PROGMEM const byte a6[8] = // array to make an arrow pointing up
{
	B11111,
	B11111,
	B11111,
	B11111,
	B11111,
	B11111,
	B00000,
	B00000

};
PROGMEM const byte a7[8] = // array to make an arrow pointing up
{
	B11111,
	B11111,
	B11111,
	B11111,
	B11111,
	B00000,
	B00000,
	B00000

};
PROGMEM const byte a8[8] = // array to make an arrow pointing up
{
	B11000,
	B01100,
	B00110,
	B11111,
	B11111,
	B00110,
	B01100,
	B11000

};
PROGMEM const byte b1[8] = // array to make an arrow pointing up
{
	B00111,
	B01111,
	B11111,
	B11111,
	B11111,
	B11111,
	B11111,
	B11111

};
PROGMEM const byte b2[8] = // array to make an arrow pointing up
{
	B11111,
	B11111,
	B00011,
	B00011,
	B00011,
	B00011,
	B11111,
	B11111

};
PROGMEM const byte b3[8] = // array to make an arrow pointing up
{
	B11100,
	B11110,
	B11111,
	B11111,
	B11111,
	B11111,
	B11111,
	B11111

};
PROGMEM const byte b4[8] = // array to make an arrow pointing up
{
	B11111,
	B11111,
	B11111,
	B11111,
	B11111,
	B11111,
	B01111,
	B00111

};
PROGMEM const byte b5[8] = // array to make an arrow pointing up
{
        B00000,
	B00000,
	B11111,
	B11111,
	B11111,
	B00000,
	B00000,
	B00000
};
PROGMEM const byte b6[8] = // array to make an arrow pointing up
{
	B11111,
	B11111,
	B11111,
	B00000,
	B00000,
	B00000,
	B00000,
	B00000

};
PROGMEM const byte b7[8] = // array to make an arrow pointing up
{
	B11111,
	B11111,
	B11111,
	B11111,
	B11111,
	B11111,
	B11110,
	B11100

};

PROGMEM const byte b8[8] = // array to make an arrow pointing up
{
	B00000,
	B00000,
	B00000,
	B00000,
	B00000,
	B11111,
	B11111,
	B11111

};


// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

void setup() {
  // set up the LCD's number of columns and rows: 
  lcd.begin(16, 2);
  // Print a message to the LCD.
  lcd.print("hello, world!");
  
  lcd.createChar(0, (byte*) pgm_read_byte(b1));
}

void loop() {
}

Ossia utilizzando type casting
lcd.createChar(0, (byte*) pgm_read_byte(b1));

Prova avedere se funziona.

Ciao,
Marco.

Ang3ls:
Fermo restando che ho provato a leggere il pdf ma non trovo affinità con la mia problematica (sicuramente per incompetenza mia) in quanto nel pdf stiamo parlando di una variabile che comunque viene richiamata per poterla scrivere... in modo "elegante" come è stato scritto qua sopra cioè attraverso macro, ma (come è giusto che sia) non si fa riferimento a caratteri speciali creati per lcd... e credo sia proprio questo il mio problema

Il pdf parla esplicitamente dell'uso di variabili con librerie che gestiscono un LCD. Il font che stai usando tu altro non è che un array di dati, ossia una variabile a matrice. E per inviarla all'LCD devi comunque richiamarla. Il problema infatti è che il codice normalmente sposta la variabile in SRAM e da lì la preleva il micro. Il problema è fargliela prelevare direttamente dalla Flash senza far "arrabbiare" il compilatore :wink:
Per questo prova come ti ha suggerito Marco.

Modificato il codice e si effettivamente compila ....
Nessun errore segnalato dal compilatore ma sul display non compaiono i caratteri speciali che ho salvato nella flash ma dei caratteri strani, infatti il tutto risulta illeggibile... In pratica ottengo lo stesso risultato come se in createchar scrivessi :

lcd.createchar(0, b1);

Uffff stavolta ci avevo effettivamente creduto

non ho provato ma prova questo:

PROGMEM byte* a1[8] = // array to make an arrow pointing up
{
	B00000,
	B11111,
	B11111,
	B11111,
	B11111,
	B11111,
	B00000,
	B00000

};
PROGMEM byte* a2[8] = // array to make an arrow pointing up
{
	B00000,
	B11100,
	B11110,
	B11111,
	B11111,
	B11111,
	B11111,
	B11111

};
PROGMEM byte* a3[8] = // array to make an arrow pointing up
{
	B11111,
	B11111,
	B11111,
	B11111,
	B11111,
	B11111,
	B01111,
	B00111

};
PROGMEM byte* a4[8] = // array to make an arrow pointing up
{
	B00000,
	B00000,
	B00000,
	B11111,
	B11111,
	B11111,
	B11111,
	B11111

};
PROGMEM byte* a5[8] = // array to make an arrow pointing up
{
	B11100,
	B11110,
	B11111,
	B11111,
	B11111,
	B11111,
	B11111,
	B11111

};
PROGMEM byte* a6[8] = // array to make an arrow pointing up
{
	B11111,
	B11111,
	B11111,
	B11111,
	B11111,
	B11111,
	B00000,
	B00000

};
PROGMEM byte* a7[8] = // array to make an arrow pointing up
{
	B11111,
	B11111,
	B11111,
	B11111,
	B11111,
	B00000,
	B00000,
	B00000

};
PROGMEM byte* a8[8] = // array to make an arrow pointing up
{
	B11000,
	B01100,
	B00110,
	B11111,
	B11111,
	B00110,
	B01100,
	B11000

};
PROGMEM byte* b1[8] = // array to make an arrow pointing up
{
	B00111,
	B01111,
	B11111,
	B11111,
	B11111,
	B11111,
	B11111,
	B11111

};
PROGMEM byte* b2[8] = // array to make an arrow pointing up
{
	B11111,
	B11111,
	B00011,
	B00011,
	B00011,
	B00011,
	B11111,
	B11111

};
PROGMEM byte* b3[8] = // array to make an arrow pointing up
{
	B11100,
	B11110,
	B11111,
	B11111,
	B11111,
	B11111,
	B11111,
	B11111

};
PROGMEM byte* b4[8] = // array to make an arrow pointing up
{
	B11111,
	B11111,
	B11111,
	B11111,
	B11111,
	B11111,
	B01111,
	B00111

};
PROGMEM byte* b5[8] = // array to make an arrow pointing up
{
        B00000,
	B00000,
	B11111,
	B11111,
	B11111,
	B00000,
	B00000,
	B00000
};
PROGMEM byte* b6[8] = // array to make an arrow pointing up
{
	B11111,
	B11111,
	B11111,
	B00000,
	B00000,
	B00000,
	B00000,
	B00000

};
PROGMEM byte* b7[8] = // array to make an arrow pointing up
{
	B11111,
	B11111,
	B11111,
	B11111,
	B11111,
	B11111,
	B11110,
	B11100

};

PROGMEM byte* b8[8] = // array to make an arrow pointing up
{
	B00000,
	B00000,
	B00000,
	B00000,
	B00000,
	B11111,
	B11111,
	B11111

};

ma ora scusate... i valori possono essere settati una sola volta per un massimo di 8 caratteri, questo vuol dire che non puoi fare un if e cambiarli a codice in corso

comunque prova a richiamare prima normalmente e poi come dice marco questo codice

Con la tua modifica mi da un errore :

error: invalid conversion from 'int' to 'byte*'

e questo errore me lo da qui:

PROGMEM byte* a1[8] = // array to make an arrow pointing up
{
	B00000,
	B11111,
	B11111,
	B11111,
	B11111,
	B11111,
	B00000,
	B00000

}; <<------------------------------ PUNTO DELL'ERRORE

Comunque ti smentisco... apparte ora con il progmem ... prima che utilizzavo la ram e normali variabili riuscivo a gestire i caratteri con un if... e tutto funzionava... L'LCD Accetta massimo 8 caratteri speciali basta capire quali vogliamo e farglieli creare all'occorrenza, ti garantisco, FUNZIONAVA TUTTO.

Ang3ls:
Con la tua modifica mi da un errore :

error: invalid conversion from 'int' to 'byte*'

e questo errore me lo da qui:

PROGMEM byte* a1[8] = // array to make an arrow pointing up

{
B00000,
B11111,
B11111,
B11111,
B11111,
B11111,
B00000,
B00000

}; <<------------------------------ PUNTO DELL'ERRORE




Comunque ti smentisco... apparte ora con il progmem ... prima che utilizzavo la ram e normali variabili riuscivo a gestire i caratteri con un if... e tutto funzionava... L'LCD Accetta massimo 8 caratteri speciali basta capire quali vogliamo e farglieli creare all'occorrenza, ti garantisco, FUNZIONAVA TUTTO.

però non andavi a modificarli, intendo che a metà programma non settavi altri caratteri personalizzati sbaglio? quando avevo provato io rompeva e non poco..
a questo punto credo sia un problema da dire: "come salva le variabili in flash? in che formato per capirci? se gli dai un byte* lo salva in int se lgi day un byte lo salva in uint8_t e se lo salviamo in uint8_t??" prova, fai prove con diversi formati e poi dicci come li compila...

Ciao,

uhm potrebbe essere un problema legato a che non riesce a caricare i valori, pur compilando.

In alternativa prova questa libreria, che dovrebbe semplificare le cose.

http://arduiniana.org/libraries/flash/

In alternativa tempo fa, per uno sketch che avevo fatto dove immaganizzavo nella memoria flash stringhe in arrivo degli SMS da confrontare avevo fatto una cosa di questo genere

// Stringhe  -> in PROGMEM
const prog_char sms_cmd_S_A[] PROGMEM = "testo 1"; // 0
const prog_char sms_cmd_S_B[] PROGMEM = "testo 2"; // 1
const prog_char sms_cmd_S_C[] PROGMEM = "testo 3"; // 3

// Tabella per fare riferimento alle stringhe comandi SMS
PROGMEM const char *sms_cmd_table[] = 
{   
  sms_cmd_S_A, // 0
  sms_cmd_S_B,
  sms_cmd_S_C
};

e poi nel codice richiamati con

(char*)pgm_read_word(&(sms_cmd_table[1]))

Ciao,
Marco.

Allora come ti ho suggerito io non può funzionare, modificandolo compileresti con successo, ma otterresti caratteri strani.

Il problema è che il medoto createChar prende come secondo argomento un puntatore ad array di uint8_t.
Il prototipo di createChar :void LiquidCrystal::createChar(uint8_t location, uint8_t charmap[])
uint8_t è sinonimo di unsigned char (ed i byte credo) entrambe sono senza segno e sono grandi 8 bit.

L'array deve per forza essere in RAM e no in PROGMEM, quindi l'unico modo artigianale è quello di fare la copia dell'array da PROGMEM a RAM. Il vantaggio viene meno solo in parte perchè possiamo utilizzare un array in ram per tutti i caratteri (array) in PROGMEM.

L'altra soluzione è modificare la libreria aggiungendo un nuovo metodo createChar, questa volta il secondo argomento deve essere un tipo che punta in PROGMEM.

La funzione incriminate è questa:

void LiquidCrystal::createChar(uint8_t location, uint8_t charmap[]) {
  location &= 0x7; // we only have 8 locations 0-7
  command(LCD_SETCGRAMADDR | (location << 3));
  for (int i=0; i<8; i++) {
    write(charmap[i]);
  }
}

Al posto di uint8_t charmap[] bisogna mettere un tipo equivalente ma mappato in PROGMEM
ed al posto di charmap usare la funzione pgm_read_byte.
Ciao.