Feb 012014
 

Come vi preannunciavo nel precedente articolo è ormai pronta la prima versione della mia nuova libreria dedicata alla shield IteadStudio 2.8 TFT Display. Anziché scrivere il codice totalmente da zero, ho preso il vecchio codice della libreria ITDB02 V1.3 da cui ho cominciato un lungo e pesante percorso di revisione. Ho scelto quella libreria in quanto era scritta in maniera elementare e mi permetteva di modificare in modo veloce il codice, partendo da una base già funzionante senza riscrivere tutto, specie la noiosa parte di inizializzazione del display.

Prestazioni e occupazione flash: prime valutazioni

Per testare le performance della libreria ho preso una delle sketch d’esempio, l’ho resa un po’ più complessa ed ho aggiunto la sezione di cronometraggio. La libreria da cui sono partito, su Arduino UNO, impiegava 11149.1ms e pesava 8732 bytes. Dopo semplici interventi di ottimizzazione e semplificazione del software il tempo è passato a 10331.8ms ed il peso della sketch a 5354 bytes. Non vi scrivo questi dati solo per la mania dei bechmark, ma per sottolineare come molto spesso le librerie che troviamo in rete siano tutt’altro che ottimizzate, infatti con poche ore di lavoro abbiamo incrementato la velocità del 7%, ma decisamente più vistosa è la diminuzione di occupazione della memoria flash di ben il 38% senza contare che la versione originale non funziona con Arduino Mega mentra la mia si. A seguito trovate numerose altre tabelle di valori, questo articolo vuole infatti mettere in luce quali possano essere i margini di miglioramento scrivendo il proprio codice in un modo o nell’altro, se non siete interessati potete tranquillamente saltare tutta questa parte.

  Velcoità ms Grandezza sketch
ITDB02 V1.3 11149.1 8732
Ss_ITDB02 V1.0 10331.8 5354

Il passo successivo è stato sostituire le classiche funzioni digitalWrite con la versione modificata presente nella mia libreria FastArduino che già conoscete in quanto integrata con la libreria hc595 che trovate in questo blog. L’utilizzo della FastdigitalWrite comporta un ulteriore notevole miglioramento della velocità con mantenimento totale della compatibilità sia con Arduino Uno che Mega. Il test viene completato in 7863.2ms mantenendo una dimensione di 5216bytes. L’iniziale incremento di velocità del 7% ora sale a quasi il 30%  con una riduzione in spazio flash di oltre il 40%. La prima semplice conclusione è che se avete una sketch che usa intensivamente le porte di Arduino in uscita vi conviene sostituire la versione originale digitalWrite con la mia FastdigitalWrite per ottenere subito guadagni che nelle applicazioni più intensive possono superare il 75%, senza compromettere la compatibilità con le diverse board.

 Arduino UNO Velcoità ms Grandezza sketch
ITDB02 V1.3 11149.1 8732
Ss_ITDB02 V1.0 10331.8 5354
Ss_ITDB02 V1.0 FA 7863.2 5216

Per andare oltre non ci si può che affidare alla programmazione diretta delle porte, cosa che ho fatto ma che ovviamente è stata aggiunta anche nelle ultime versioni della libreria ufficiale, la UTFT. E qui le divergenze diventano interessanti e sono il motivo per cui vi ho annoiato con tutti questi numeri. La programmazione diretta delle porte complica notevolmente il codice e determina grossi problemi nel rendere il codice compatibile con le varie schede. La domanda a questo punto è: che velocità raggiunge la UTFT? Ve lo dico io: 903.7ms ma con una sketch di ben 19682bytes. Ci troviamo di fronte ad un netto miglioramento di velocità ma con un pesantissimo impiego di risorse. E la mia libreria? Vi sorprenderà, raggiunge i 531.9ms in soli 4944bytes, quindi prestazioni ancora migliori con ulteriore risparmio di risorse. Ovviamente la UTFT contiene moltissime funzioni non ancora presenti nella mia libreria, ma nel momento in cui non vengono usate NON devono occupare spazio nella sketch finale. Questi test li ho fatti con l’abbozzo iniziale della mia libreria, per cui posso attendermi una certa flessione prestazionale ma in linea di massima non dovrebbero esserci stravolgimenti di questi valori, altrimenti tutto questo lavoro di ottimizzazione non avrebbe alcun senso.

 Arduino UNO Velcoità ms Grandezza sketch Speed% Sketch%
ITDB02 V1.3 11149.1 8732 base base
Ss_ITDB02 V1.0 10473.3 5326 -7.3% -38.7%
Ss_ITDB02 V1.0 FA 7863.2 5216 -29.5% -40.3%
UTFT 903.7 19682 -91.9% +125.4%
Ss_ITDB02 V1.0 FADP 531.9 4944 -95.2% -43.4%

Ma non finisce qui. Come dicevamo la mia libreria funziona anche su Mega e su shift register, per cui abbiamo altre tre tabelline piene di dati da studiare. Anche se la versione originale della libreria ITDB non funziona con la Mega ne tantomeno su HC595, ne ho mantenuto i dati come riferimento iniziale:

 Arduino Mega Velcoità ms Grandezza sketch Speed% Sketch%
BASE 11149.1 8732 base base
Ss_ITDB02 V1.0 13735.3 5602 +23.2% -35.8%
Ss_ITDB02 V1.0 FA 7870.5 5330 -29.4% -39.0%
UTFT 1179.9 20224 -89.4% +131.6%
Ss_ITDB02 V1.0 FADP 1198.3 5302 -89.3% -43.4%

Guardando questi dati una cosa risulta chiara. Indipendenemente dalla libreria e dal tipo di ottimizzazzioni, la versione per Arduino Mega è sempre più lenta ed impiega maggiori risorse. Altra cosa interessante è notare che la mia libreria funziona su shift register il 76% più velocemente della libreria iniziale con collegamento diretto.

HC595 Velcoità ms Grandezza sketch Speed% Sketch%
BASE 11149.1 8732 base base
Ss_ITDB02 V1.0 30163.8 6364 +170.5% -27.1%
Ss_ITDB02 V1.0 FA 7127.3 6260 -36.1% -28.3%
UTFT XX XX XX XX
Ss_ITDB02 V1.0 FADP 2590.0 6052 -76.8% -30.7%

Come ultima tabella vi metto a confronto le versioni più performanti sulle diverse board:

Comparativa Velcoità ms Grandezza sketch
Ss_ITDB02 – Mega 1198.3 5302
UTFT – Mega 1179.9 20224
Ss_ITDB02 – UNO 531.9 4944
UTFT – UNO 903.7 19682
Ss_ITDB02 V1.0 HC595 2590.0 6052

Ci sono diverse considerazioni che possiamo fare su questi dati. La prima è che la UTFT spreca enormi quantità di risorse e questo è un lato sicuramente negativo anche perché risulta chiaro che l’occupazione di memoria è riducibile del 75% per fare le stesse cose. Non ho ancora indagato il motivo di tale spreco, è possibile che si tratti dei font aggiuntivi, ma nel momento in cui non vengono utilizzati dalla sketch non ha senso che vengano compilati.  Per fortuna non ho notato sprechi sul versante RAM, infatti le differenze con la mia libreria sono irrisorie (una decina di bytes). L’altra cosa che possiamo notare è che la libreria UTFT non è ottimizzata al massimo su Arduino UNO, cosa seccante visto che la shield è in prima istanza fatta proprio per quella board. La versione Mega è solo dello 0.1% più veloce della mia libreria (almeno per ora 🙂 ) ma ha un’occupazione di memoria flash quasi 4 volte superiore. Vi siete chiesti perché la mia libreria è oltre due volte più veloce sulla UNO che sulla Mega? Ve lo dico io. Nella UNO gli 8 pin corrispondenti agli ingressi dati del display sono tutti sulla stessa porta per cui con un’unica assegnazione li posso settare tutti in contemporanea, cosa impossibile da farsi sulla Mega dove sono mescolate tre porte diverse. IMAG0857Questo ci spiega perché hardware di sviluppo generico come Arduino e le relative shield  possano essere decisamente meno efficienti di schede create ad OK per specifici compiti, anche a parità di processore, quarzo, etc. Vorrei anche sottolineare che la versione HC595 (foto qui sopra)  tutto sommato ha una velocità che è solo la metà di quella della versione Mega, per cui possiamo affermare che rinunciando al 50% delle performances possiamo risparmiare 5 pin digitali, anche se purtroppo occorrerà dell’hardware di supporto per adattare la shield. Qui sopra vedete all’opera il mio solito prototipo che al momento della foto ha montata la shield con il display, due 74hc595 in serie di cui il primo collegato al display, un 74hc165 con 8 ingressi digitali ed un trasmettitore infrarossi. Direi che è un bel passo avanti rispetto a quanto ci obbliga la shield ed il software originale anche se non ho ancora cominciato a testare touch ed SD.

Disegno e font

Ovviamente avere un display di questo tipo e gestire “a mano” ogni singolo pixel nella propria sketch non ha nessun senso. E’ necessario avere una base software che ci permetta di tracciare linee, creare cerchi, rettangoli e scrivere lettere o numeri, tutte cose che a basso livello vanno fatte settando i colori dei singoli pixel. Rispetto alle librerie originali non sono riuscito ad ottenere che minimi vantaggi prestazionali, impercettibili se non con un preciso cronometraggio per cui non ci sono sorprese nel disegno delle figure geometriche basilari. La cosa dove ho invece modificato pesantemente tutto il codice è la gestione dei font. La UTFT ha un suo sistema di gestione dei font che ha un piccolo grosso difetto: l’occupazione di memoria flash. I programmatori hanno infatti optato per registrare in flash i caratteri bitmap da scrivere sullo schermo, cosa del tutto condivisibile visto che la memoria ram è molto scarsa.font_example Il problema è che per ogni singolo pixel di ogni carattere di ogni font, dobbiamo usare un bit. Se sommiamo tutti i bit di tutti i caratteri di tutti i font, specie quelli di dimensioni maggiori, vediamo che l’occupazione di memoria diventa considerevole. Io ho cercato una soluzione decisamente diversa al problema. Per quanto riguarda i numeri a segmenti forniti con la UTFT, ho sviluppato un algoritmo di disegno vettoriale, in questo modo a fronte di una maggior complessità del codice vi è una marcata riduzione nell’occupazione di memoria, inoltre oltre ai soli numeri sono state codificate tutte le lettere sia maiuscole che minuscole ed alcuni simboli senza contare la possibilità di decidere lo spessore dei segmenti, lo spazio che li separa, le dimensioni sull’asse X ed Y, etc. Per quanto riguarda i font bimap ho mantenuto quello più piccolo di cui ho modificato alcuni caratteri per una miglior visibilità. Ho invece cancellato del tutto il font più grande ma ho introdotto un algoritmo che a partire da quello piccolo permette di radoppiare la larghezza, l’altezza o entrambe. Per quanto riguarda il raddoppio della sola larghezza o altezza viene semplicemente visualizzata due volte la riga o la colonna aumentando lo spessore dei tratti. Per quanto riguarda la moltiplicazione di entrambe, invece, non mi sono limitato ad un semplice raddoppio dei pixel, altrimenti i caratteri sarebbero risultati troppo “quadrettati”, ma ho creato un algoritmo che cerca di mantenere delle linee sottili e pulite, come potete vedere nella figura qui a fianco (scritte test 4 e MCMAJAN.COM). Penso di poter affermare che il risultato è davvero buono, specie se teniamo in considerazione il fatto che non c’è alcun incremento di memoria occupata se non quello per la routine che disegna i caratteri. Ho volutamente deciso di mantenere la possibilità di aggiungere font bitmap aggiuntivi, ciò comporta una minor ottimizzazione del codice con un leggero impatto negativo sulle prestazioni, ma permette a chiunque di aggiungere nuovi font o espandere quello presente in base alle relative esigenze, cosa che potrebbe permettere l’aggiunta di nuovi font su schede basate di maggior quantità di memoria o su scheda SD esterna. In realtà non ho ancora preparato delle funzioni specifiche per l’aggiunta di nuovi font senza dover modificare il codice della libreria, ma provvedereò in una delle prossime release, sempre che questo lavoro trovi un certo interesse nella comunità Arduino.

Orientamento

Come nella UTFT ho introdotto la possibilità di usare lo schermo sia in verticale (Portrait) che orizzontale (Landscape), è perciò possibile utilizzare il display con entrambi gli orientamenti senza alcuna modifica del codice se non il settaggio dell’orientamento stesso. Basta una sola istruzione per modificare l’orientamento dello schermo ed in automatico le coordinate verranno adattate per disegnare gli elementi grafici con l’orientamento desiderato.

Touch Screen

Per quanto riguarda il touch screen l’implementazione originale ITDB02 non l’ho presa nemmeno in considerazione tanto era arretrata, invece quella presente nella UTF non permette l’utilizzo per fini commerciali e dato che non voglio precludermi la possibilità un giorno di creare dei miei prodotti e metterli in vendita, ho deciso di scrivere da zero la gestione del TouchScreen. Devo dire che credevo fosse più semplice, ho avuto non poche difficoltà. Allo stato attuale delle cose diciamo che il sistema funziona, non mi entusiasma per velocità ma non ho ancora implementato la programmazione diretta delle porte. Il sistema di calibrazione funziona ma è un po’ impreciso, devo lavorarci ancora ma il supporto c’è e funziona per cui se dovete creare delle aree sensibili sullo schermo il funzionamento è assicurato. Gli unici problemi sorgono se dovete creare un sistema che “segue” in modo rapido il movimento di una penna o il dito sullo schermo, ad esempio se tentate di creare un programma che crea una traccia sotto il dito noterete che fra i punti restano dei punti vuoti in quanto il sistema non legge i dati con sufficiente velocità., ma abbiate pazienza, è solo la prima versione.

SD

Per terminare  veniamo al supporto SD. Con la UTFT c’è una libreria apposita, la UTF_TinyFAT che però non supporta SD superiori a 2GB. Ma nell’IDE di Arduino c’è già una libreria SD bella che pronta quindi la mia domanda è: perché scriverne un’altra?  La cosa più sensata è aggiungere eventualmente delle funzioni specifiche, come ad esempio quelle dedicate a prelevare un’immagine dalla SD e disegnarla sullo schermo. Purtroppo parliamo di una libreria molto pesante in termini di occupazione di memoria flash, ma con l’importante snellimento che ho ottenuto sul core della mia libreria rispetto alla UTFT sono riuscito ad utilizzare la SD senza problemi in contemporanea al display, cosa che non ero riuscito a fare con la libreria originale. Non ho studiato il funzionamento della libreria in questione e non ne ho analizzato i listati per cui non ho idea se si possa fare anche qui una bella opera di snellimento, ma già il fatto che sia riuscito a compilare un esempio che permette di usare la SD e lo schermo in contemporanea è un buon risultato visto che con la libreria originale non ero riuscito a farlo. Nelle prossime versioni vedrò se ci sono margini di miglioramento ed eventualmente, come accennavo, scriverò delle funzioni per visualizzare sul display immagini memorizzate nella SD, ma per ora mi limito a distribuire alcuni esempi della libreria originale, riadattati per mandare l’aoutput sullo schermo anzichè sulla porta seriale.

NOTA: Su Arduino Mega l’SD NON funziona, purtroppo i pin hardware SPI fra Arduino UNO e Mega sono differenti e su questo non ci posso fare nulla. Ci sarebbero due possibili soluzioni. Una è creare una shield intermedia che modifica a livello hardware l’assegnazione dei pin, volendo esistono prodotti già pronti allo scopo come questo. L’altra alternativa è modificare il software per far funzionare l’SPI “a mano” su pin diversi da quelli hardware. Purtroppo però dobbiamo modificare un sacco di cose per cui è una soluzione improponibile in tempi brevi.

Manca qualcosa?

No non manca molto. Devo scrivervi una pagina apposta per mantenere la libreria in cui vi spiegherò tutti i comandi e gli schemi di collegamento nel caso di uso con 74HC595. Devo ancora scrivere alcuni esempi per l’utilizzo della libreria e poi metterò a disposizione il link per il download. Dovrete avere ancora un po’ di pazienza visti gli impegni lavorativi, ma la libreria è ormai pronta e presto potrete provarla con mano.