Buonasera, vorrei arricchire un piccolo progetto che ho fatto con un Arduino Nano e due display OLED. Purtroppo l'utilizzo dei font insieme al codice hanno saturato la memoria flash. Vorrei utilizzare una eeprom esterna per memorizzare le bitmap e quindi liberare memoria per il codice.
Utlizzo dei display OLED da 128x32 pixel monocromatici gestiti dalle librerie <Adafruit_GFX.h> e "Adafruit_SSD1306.h".
Mi chiedo se è possibile, senza dover necessariamente riscrivere le librerie se vi è un modo veloce per far puntare per esempio la funzione :
display.drawBitmap(posx, posy, bitmap pointer array, 128, 32, color foreground, color background);
La bitmap è definita come un array di byte ed è appunto memorizzata in flash, questa è la dichiarazione:
const uint8_t bitmap[] PROGMEM = {......};
Ora vedo un paio di soluzioni, la prima è modificare pesantemente la libreria e fare in modo che acceda direttamente alla eeprom e si legga i dati, la seconda e copiare temporaneamente la bitmap dalla eeprom alla RAM e passare il puntatore alla funzione, in modo da non toccare la libreria. In questo secondo caso, sicuramente più rapido da iplementare c'è il vincolo che vado ad occupare circa mezzo kbyte, cmq troppo.
Dopo la spiegazione, chiedo se qualcuno ha già fatto qualcosa di simile, anche con altre librerie, o se semplicemente ha qualche consiglio. Non mi va di re-inventare l'acqua calda. Grazie a tutti e buona serata.
Buonasera e benvenuto,
essendo il tuo primo post, nel rispetto del regolamento della sezione Italiana del forum (… punto 13, primo capoverso), ti chiedo cortesemente di presentartiIN QUESTO THREAD (spiegando bene quali conoscenze hai di elettronica e di programmazione ... possibilmente evitando di scrivere solo una riga di saluto) e di leggere con molta attenzione tutto il su citato REGOLAMENTO ... Grazie.
Guglielmo
P.S.: Ti ricordo che, purtroppo, fino a quando non sarà fatta la presentazione nell’apposito thread, nessuno ti potrà rispondere, quindi ti consiglio di farla al più presto.
Presentazione fatta, o dovrei dire ri-fatta visto che alla fine oggi mi sono riregistrato. Avevo una login creata qualche anno fa, probabilmente non frequentando per molto tempo il sistema mi ha cancellato. Cmq no problem.
Enrico.
copiare temporaneamente la bitmap dalla eeprom alla RAM e passare il puntatore alla funzione, in modo da non toccare la libreria.
Temo che non si possa fare nemmeno questo, aldilà del problema della memoria occupata, la documentazione di Adafruit dice :
The bitmap data must be located in program memory using the PROGMEM directive.
Peccato, perchè altrimenti sarebbe stata una soluzione da tentare : creare un buffer in RAM che contenga una o più righe del bitmap ( a seconda di quanta memoria puoi spremere), copiarci dati dalla eeprom, disegnare il bitmap parziale e ripetere l'operazione fino a completamento.
ilguargua:
Temo che non si possa fare nemmeno questo, aldilà del problema della memoria occupata, la documentazione di Adafruit dice :Peccato, perchè altrimenti sarebbe stata una soluzione da tentare : creare un buffer in RAM che contenga una o più righe del bitmap ( a seconda di quanta memoria puoi spremere), copiarci dati dalla eeprom, disegnare il bitmap parziale e ripetere l'operazione fino a completamento.
Ciao, Ale.
Già, grazie comunque per la risposta. Prima di mettermi giù a riscrivere una funzione cercando di mantere la filosofia della libreria, volevo capire se qualcuno si fosse già cimentato. Lo scopo era aggiungere qualche bitmap ad un progettino già realizzato ma che per mancanza di memoria non ho potuto completare come mi piaceva. Sarebbe un esercizio interessante e magari anche utile ad altri. Bisogna evitare comunque di passare per la flash.
Enrico.
Comunque, se guardi come è implementato il metodo drawBitmap() (in Adafruit_GFX.cpp ) vedi che non è cosi difficile riscriverlo per il tuo scopo :
void Adafruit_GFX::drawBitmap(int16_t x, int16_t y, const uint8_t bitmap[],
int16_t w, int16_t h, uint16_t color) {
int16_t byteWidth = (w + 7) / 8; // Bitmap scanline pad = whole byte
uint8_t byte = 0;
startWrite();
for (int16_t j = 0; j < h; j++, y++) {
for (int16_t i = 0; i < w; i++) {
if (i & 7)
byte <<= 1;
else
byte = pgm_read_byte(&bitmap[j * byteWidth + i / 8]);
if (byte & 0x80)
writePixel(x + i, y, color);
}
}
endWrite();
}
Nella tua funzione bitmap anzichè essere un array di byte sarà l'indirizzo dell'immagine nella eeprom, poi basta sostituire pgm_read_byte() con EEPROM.read() (se usi la eeprom interna, altrimenti un altra funzione specifica che legga il byte dalla eeprom).
ilguargua:
... se usi la eeprom interna, altrimenti un altra funzione specifica che legga il byte dalla eeprom.
... credo che la prima gli sia insufficiente come capacità, mentre la seconda opzione protrebbe creare qualche problema.
C'è infatti da verificare COME parla con la memoria esterna dato che, se ben ricordo, ma non ho ricontrollato, l'invio dei vari bytes di una bmp verso il SSD1306 avvenga all'interno di una singola "data transfer sequence" I2C e quindi ... se la memoria esterna si legge in SPI il gioco potrebbe funzionare, se la memoria esterna si legge anche essa in I2C ... credo saltino fuori dei bei problemi ... :
ilguargua:
Comunque, se guardi come è implementato il metodo drawBitmap() (in Adafruit_GFX.cpp ) vedi che non è cosi difficile riscriverlo per il tuo scopo ....
Grazie Ale, potrebbe essere effettivamente più semplice, farò dei test. Grazie.
enry68:
Non vedo il problema, hanno indirizzi differenti.
Vedo che NON hai prestato attenzione a quanto ho scritto ...
... che abbiano indirizzi diversi è più che ovvio, che tu, nel mezzo di una singola "data transfer sequence" (quindi dopo l'invio dello START, nel corso del "Send Data" e prima dello STOP) possa indirizzare qualche altra cosa lo vedo ben più complesso ... :
Ovviamente, come ho detto, vado a memoria ed occorrerebbe verificare se l'invio della bmp è, appunto, in una una singola "data transfer sequence" ...
>enry68: Quando si quota un post, NON è necessario riportarlo (inutilmente) tutto; bastano poche righe per far capire di cosa si parla ed a cosa ci si riferisce, inoltre, se si risponde al post immediatamente precedente, normalmente NON è necessario alcun "quote" dato che è sottinteso.
Gli utenti da device "mobile" (piccoli schermi) ringrazieranno per la cortesia
Guglielmo
P.S.: Ho troncato io i "quote" dei tuoi post qui sopra
gpb01: V, che tu, nel mezzo di una singola "data transfer sequence" (quindi dopo l'invio dello START, nel corso del "Send Data" e prima dello STOP) possa indirizzare qualche altra cosa lo vedo ben più complesso ... :
Scusa Gugliemo, perchè dovrei fare una "porcata" del genere ?
Evidentemente ci deve essere stato un malinteso. Nessun tipo di nexting. Grazie comunque della preoccupazione.
avvenga all'interno di una singola "data transfer sequence" I2C
Questo potrebbe essere un problema, perlomeno usando eeprom I2C, ed in effetti quella startWrite() e endWrite() sembrano indicare una cosa del genere. Un possibile rimedio (a parte usare eeprom SPI) potrebbe essere di usare un ulteriore loop esterno ai 2 for{} esistenti in cui leggere la eeprom trasferendo in memoria le linee possibili (dipende da quanta RAM si ha a disposizione) e poi scrivere la bitmap un pezzo alla volta. Probabilmente non il massimo della vita in quanto a velocità, ma potrebbe funzionare.
enry68:
Scusa Gugliemo, perchè dovrei fare una "porcata" del genere ?
Non è che la fai tu, è che le funzioni che trasferiscono le bmp al SSD1306, normalmente (tutte quelle che ho visto ed anche tutte quelle che ho scritto), per ovvie ragioni di velocità fanno START e restano in "data sendig" per tutta la bmp ... quindi, contrariamente alla PROGMEM, in cui uno riesce a leggere byte a byte la PROGMEM e trasferirla al display, con un EEPROM I2C ... è praticamente impossibile. Come detto. con una SPI (... e ce ne sono di ottime) il problema non si pone
ilguargua:
... Un possibile rimedio (a parte usare eeprom SPI) potrebbe essere di usare un ulteriore loop esterno ai 2 for{} esistenti in cui leggere la eeprom trasferendo in memoria le linee possibili ...
Vero, ma, oltre ad essere sicuramente più lento, comporta delle correzioni ancora più pesanti dati che devi trasferire piccoli blocchi, ogni volta calcolando il nuovo offset dove andare a scrivere nella memoria del SSD1306 ... :
Ripeto, secondo me la cosa più semplice è usare una EEPROM SPI e si può andare alla massima velocità, senza andare a stravolgere troppo la logica delle funzioni preesistenti