Libreria display OLED per ORbit16™ / PIC24F / PIC32MX

Ho caricato sul sito di ORbit16™ una libreria, in versione preliminare, per utilizzare il display UG-2864 della Univision, basato sull’oramai diffusissimo controller SSD1306 appositamente progettato per i display OLED monocromatici. I display OLED pare siano il futuro: sottilissimi e leggeri, bassissimo consumo, non hanno bisogno di retroilluminazione in quanto i singoli pixel “brillano di luce propria”, elevato contrasto (il nero è davvero nero in quanto il pixel è spento materialmente, a differenza di un display retroilluminato in cui la retroilluminazione è sempre presente) ed elevata visibilità in ogni condizione di illuminazione esterna. Dicevo: preliminare in quanto, come per il controller PCD8544 ho incluso soltanto funzioni di scrittura e qualche piccola funzione grafica, predisponendo il tutto per future implementazioni grafiche (linee, quadrati ecc), tempo permettendo, che richiedono l’implementazione di un buffer in ram e l’esecuzione di tutte le operazioni su questo anzichè direttamente nella ram del display.

Il controller SSD1306

Questo controller, prodotto dalla cinese Solomon Systech, è progettato per il controllo di pannelli OLED monocromatici con una risoluzione massima di 128×64 pixel. Include delle piccole funzioni di accelerazione grafica (scrolling), uno stadio di boost per l’alimentazione del pannello e la possibilità di essere pilotato in SPI, I2C o in parallelo, anche se il sistema più utilizzato è l’ SPI in quanto consente una velocità maggiore ed è meglio documentato. La mia libreria, come quella del PCD8544, sfrutta un SPI emulato, che è più semplice e può essere facilmente portato anche su altri picmicro e altre piattaforme.

La libreria OLED per ORbit16

Il display utilizzato nei miei studi è un UG-2864 prodotto dalla taiwanese (per non dire di nuovo cinese) Univision, che ha un pannello OLED da 128×64 pixel, 0.96 pollici, e si trova in commercio con i pixel nella colorazione blu, bianca e blu con la prima riga di colore giallo/arancione (quest’ultimo tipo l’ho visto montato su un pulsiossimetro da dito da un pediatra).

Immagine prelevata dal sito ebay del venditore linkato più in basso

Specifico che questo tipo di display si trova su Ebay, solo pannello, intorno ai 5/7 euro (questo qui ad esempio). Ma si tratta di un pannello che termina con un flat cable, forse un po’ difficile da utilizzare da chiunque (ma non impossibile!) e che comunque richiede una piccola circuiteria esterna. Io ho acquistato un modello in cui il pannello è montato su una breakout board (proprio quello dell’immagine sopra), che riporta già tutta la circuiteria necessaria per poter essere utilizzato e in più riporta la piedinatura su un passo standard da 1″, utilizzabile anche su breadboard (in particolare io ho acquistato questo). Per cui mi riferirò a quest’ultimo tipo di display e non al solo pannello OLED. Questo tipo di display, inoltre, è anche presente nel modello da 1.3″, più grande, ma dal costo ancora forse eccessivo (circa €20).

La mia libreria non può essere utilizzata con display basati su SSD1306 aventi l’alimentazione separata del pannello (come il PMod oled della Digilent), ma può diventarlo con opportune modifiche (l’aggiunta di un pin che controlla un transistor per alimentare la seconda linea, da configurare opportunamente e con le giuste temporizzazioni durante l’inizializzazione).

Le linee da utilizzare per il controllo sono 4: la linea ingresso dati (identificata sul mio display come D1/SDIN, ma che potrebbe anche essere indicata su altri display come MOSI – Master Output Slave Input), la linea ingresso clock (indicata come D0/SCLK), la linea di reset (indicata come RES) e la linea Register Select (indicata come RS -da non confondere con RES- che potrebbe essere indicata su altri display come D/C o DC : Data/Command).

Il display da me usato ha più linee di alimentazione: noi dobbiamo collegare soltanto il pin con l’indicazione 3V3 e lasciare assolutamente scollegato il pin VIN (lo specifico perchè può creare confusione). La linea di Chip Select (indicata come CS) ho previsto di collegarla a massa e risparmiare così un 5° pin, ma se dovete collegare sul bus SPI più di un dispositivo, allora il pin CS (attivo basso) deve essere pilotato dalla MCU e quindi prima di ogni operazione sul display dovete portarla a livello basso (per selezionare il display) e quindi a livello alto non appena avete finito di operare sul display.

La libreria consta di due files: oled.h e oled.c. ed è scritta per poter essere utilizzata sia col PIC24FJ che col PIC32MX senza apportare modifiche in quanto ho usato notazioni standard che vanno bene per entrambi i compilatori MPLAB C30 e MPLAB C32.

La libreria, in teoria, dovrebbe poter essere utilizzabile anche sui PIC18 senza fare modifiche. Per i PIC16 bisogna modificare le definizioni delle porte, in quanto i vecchi PIC16 non hanno i registri LAT (sono stati introdotti sui nuovi, sempre più simili ai PIC18). Inoltre per i PIC16 potreste avere malfunzionamenti se le linee di controllo non appartengono allo stesso banco di porte.

In oled.h vanno selezionate tutte le preferenze:

Scelta del font

Ho realizzato due font da utilizzare per la scrittura standard: uno da 5×8 (in realtà è definito come 5×8 ma usato come 6×8 in quanto dalle funzioni viene aggiunta una colonna vuota sulla destra per non far attaccare i caratteri) e uno da 8×8 pixels. Il font 5×8 è lo stesso utilizzato nella libreria del display nokia PCD8544 (che ho disegnato sulla falsariga del set caratteri HD44780), ma per questo tipo di display non è molto adatto in quanto la larghezza di 6 pixel non consente di utilizzare la riga del display oled per intero (con 128 pixel di larghezza si potrebbero utilizzare 21 caratteri e rimarrebbero vuoti 2 pixel) e, dato che il display ha la diagonale di 1″ quindi piccolo, non è poi molto visibile.

Set caratteri del font 5x8

Ho così disegnato un secondo font, da 8×8 pixels, che risulta molto più visibile e consente 16 caratteri per riga (e il display può quindi essere usato come un display a caratteri da 16 caratteri per 8 righe):

Set caratteri del font 8x8

Entrambi i font contengono il set di caratteri dal n°32 (spazio) al n°127. I caratteri 126 (0x7E) e 127 (0x7F) li ho disegnati come “freccia sinistra” e “freccia destra” (normalmente rappresentano rispettivamente i caratteri tilde ~ e il carattere invisibile DELETE). Il carattere 92 (0x5C) l’ho disegnato come simbolo del grado (normalmente rappresenta il carattere di backslash \ raramente utilizzato). La selezione del font va eseguita in oled.h commentando il font che non vogliamo utilizzare:

35
36
37
38
39
40
// **********************************************************************
// STANDARD FONT - INCLUDE ONLY ONE!
// **********************************************************************
 
//#include "font8x5.h"
#include "font8x8.h"

Selezione linee dati

Come detto, la mia libreria non prevede l’utilizzo della linea CS, che deve quindi essere collegata a massa. Vanno quindi scelti i 4 I/O da utilizzare scegliendo i registri LAT e quindi i registri TRIS associati:

42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
// **********************************************************************
// HARDWARE SETTINGS
// **********************************************************************
 
// Display lines to ORbit16 lines
#define	OLED_RS			LATAbits.LATA0		// Register Select	        RS/DC
#define	OLED_RESET		LATAbits.LATA1		// Reset			RES
#define	OLED_CLOCK		LATBbits.LATB0		// Clock			D0/SCLK
#define OLED_DATAIN		LATBbits.LATB1		// Data in			D1/SDIN/MOSI
 
// TRIS ports to OLED ports
#define TRIS_OLRS		TRISAbits.TRISA0	// Register Select	        RS/DC
#define TRIS_OLRES		TRISAbits.TRISA1	// Reset			RES
#define TRIS_OLCLK		TRISBbits.TRISB0	// Clock			D0/SCLK
#define TRIS_OLDIN		TRISBbits.TRISB1	// Data in			D1/SDIN/MOSI

Di default la libreria prevede il collegamento della linea Register Select ad A0/P5 (RA0), linea Reset su A1/P6 (RA1), linea clock su BP0 (RB0) e linea dati su BP1 (RB1).

Preferenze e Font Maxi.

Questi parametri vanno impostati in questa sezione:

60
61
62
63
64
65
66
67
// **********************************************************************
// DISPLAY PREFERENCES
// **********************************************************************
 
#define OLED_NEGATIVE	0		// 1 if you want to use negative display
#define DISPLAY_WIDTH	128		// panel width, in pixel
#define DISPLAY_HEIGHT	64		// panel height, in pixel
#define USE_BIG_FONT			// comment if you don't want the big font

La macro OLED_NEGATIVE, se impostata a 1 inizializza il display in negativo (ovvero quando cancellate il display, tutti i pixel vengono accesi anzichè spenti). DISPLAY_WIDTH e DISPLAY_HEIGHT sono espressi in pixel e specificano le dimensioni del display. La macro USE_BIG_FONT consente di utilizzare il font grande, 16×16, che comprende i caratteri con codice ASCII da 44 a 58 (numeri e i seguenti simboli: virgola, punto, trattino/meno, simbolo del grado al posto dello slash / e due punti. Non è incluso lo spazio), questo può essere utile per orologi o per mostrare valori analogici. Se la commentate risparmiate un bel po’ di memoria in quanto la tabella font e la relativa funzione non vengono caricate.

Funzioni

Le funzioni che prevedono un posizionamento per la scrittura caratteri (come la oled_goto(x,y)), richiedono che il valore di ascissa (x) sia espresso in pixel da 0 a DISPLAY_WIDTH-1 (quindi da 0 a 127 nel caso di un display da 128×64) e che il valore di ordinata (y) sia espresso in righe da 8 pixel, quindi da 0 a (DISPLAY_HEIGHT/8)-1 (ovvero da 0 a 7 nel caso di un display da 128×64). Questo consente di posizionare anche i caratteri a metà strada orizzontalmente ed ottenere quindi delle scritte perfettamente centrate nel display senza essere costretti a spaziature dettate dalla larghezza del font.

Ci sono quindi le classiche funzioni di scrittura che consentono di scrivere un singolo carattere, una stringa, un numero intero con segno o senza segno e in più ho aggiunto una funzione per scrivere con allineamento orizzontale al centro (funziona per ora solo col font standard):

void oled_putch(unsigned char c); // scrive un singolo carattere. Ricordo: da includere in apici singoli: 'A'
void oled_puts(char *s); // scrive una stringa. Ricordo: da includere in apici doppi: "stringa"
void oled_puts_center(char *s, unsigned char y); // scrive una stringa allineata al centro sulla riga y
void oled_putun(unsigned int c); // scrive un numero intero senza segno
void oled_putsn(signed int c); // scrive un numero intero con segno

Le funzioni oled_bitmap e oled_icon operano allo stesso, identico, modo di quelle per il display PCD8544 (leggete la documentazione presente qui per capire come creare immagini da utilizzare con queste due funzioni).

Ci sono due funzioni di cancellazione: oled_clear() che cancella tutto lo schermo, e oled_clear_row(y) che cancella solo la riga y.

La funzione oled_scrollh(direction, delay, rowstart, rowend) consente di eseguire lo scrolling hardware in orizzontale sfruttando le funzioni di accelerazione grafica integrate nel controller SSD1306. Il parametro direction va impostato con i valori SCROLL_RIGHT (scroll da sinistra verso destra) o SCROLL_LEFT (da destra verso sinistra). Il parametro delay va impostato con il valore SCROLL_DELAY_x, dove x è un numero da 1 (scroll più veloce) a 7 (scroll più lento). I parametri rowstart e rowend vanno impostati rispettivamente con il numero di riga di partenza e di fine. Se si vuole, ad esempio, eseguire solo lo scrolling della prima riga, rowstart e rowend vanno impostati entrambi a zero; mettendo 1 come valore di rowstart e 3 come rowend, le righe 0,4,5,6 e 7 rimangono fisse e vengono fatte scrollare le righe dalla seconda alla quarta; mettendo rowstart=0 e rowend=7 viene fatto scrollare tutto lo schermo.

Le funzioni di scroll, da mie prove effettuate, pare non siano compatibili con il goto: in pratica se in un loop aggiornate continuamente lo schermo con funzioni goto e contemporaneamente è in corso lo scroll, la ram del display viene corrotta e dopo un po sul display vengono visualizzati pixel caso. Non sono riuscito a spiegarmi questo comportamento anomalo e sui datasheet non c’è menzione di questo malfunzionamento.

Il solo scroll verticale pare non possa essere realizzato (anche se mi pare strano), dato che nel set di funzioni è previsto piuttosto uno scroll sia orizzontale che verticale contemporaneamente: l’ho provato e non l’ho trovato di particolare interesse per cui non l’ho incluso.

Ho incluso una funzione oled_plot(x,y) per disegnare un punto, in cui x va da 0 a 127 e y da 0 a 63, ma non è molto utile in quanto non avendo strutturato il tutto per utilizzare un buffer in ram dal quale trasferire i dati, le funzioni sovrascrivono il contenuto nelle locazioni indirizzate, per cui, ad esempio, non è possibile disegnare due punti adiacenti verticalmente perchè il secondo punto disegnato sovrascriverebbe l’intera colonna di 8 pixel cancellando il punto precedente.

Altre funzioni, implementate come macro, e quindi da scrivere senza argomento (la doppia parentesi alla fine!), sono:

oled_scrollstop; // ferma lo scrolling
oled_on; // accende il pannello oled
oled_off; // spegne il pannello oled (ma i dati rimangono in memoria)
oled_nop; // nop
oled_negative; // passa il pannello in visualizzazione negativa
oled_normal; // passa il pannello in visualizzazione positiva/normale

Sono quindi presenti due variabili globali da utilizzare per modificare il comportamento di alcune funzioni. Le variabili sono: oled_inverted e oled_font. Queste due variabili vanno settate/resettate prima di ogni funzione di scrittura. oled_inverted posta a 1 scrive in negativo i caratteri passati alle funzioni di scrittura (è diversa dalla macro oled_negative, che passa in negativo l’intero display sfruttando l’accelerazione hardware del controller). oled_font è da utilizzare soltanto se è stata abilitata la macro USE_BIG_FONT e consente di selezionare, per le funzioni di scrittura, il font standard (oled_font=0 oppure oled_font=FONT_STD – valore di default) o il font 16×16 (oled_font=1 oppure oled_font=FONT_BIG).

Demo

La demo illustra l’utilizzo di tutte queste funzioni. Sono presenti due progetti MPLAB : uno per il PIC32MX250F128B (OLED_demo_PIC32MX250F128B.mcp) e uno per il PIC24FJ64GB002 (OLED_demo_PIC24FJ64GB002.mcp). Se usate pic appartenenti alle stesse famiglie ma diversi, selezionate il progetto del pic più consono e cambiate il modello di picmicro dal menù Configure -> Select Device e ricompilate. In particolare il progetto del PIC24FJ64GB002 fa uso del bootloader USB (quindi è adatto solo al 24FJ64GB002), mentre quello del PIC32MX250F128B è impostato per usare il Pickit3.

Il file main.c è lo stesso per entrambi i picmicro, potete vedere che seleziono le funzioni da utilizzare per l’uno o per l’altro tipo di compilatore sfruttando le macro __C30__ e __C32__ create in automatico dai compilatori MPLAB C30 e MPLAB C32. La demo, alla fine, sfrutta le funzioni RTCC (Real Time Clock Calendar), ed è quindi necessario che la vostra ORbit16™ abbia montato l’oscillatore secondario (quarzo Q2 da 32768Hz e condensatori C12 e C13). In particolare col PIC24FJ e i quarzi che normalmente fornisco, mi sono trovato bene con i condensatori ceramici da 12pF. I nuovi PIC32 che mi sono arrivati, con queste due capacità non riescono ad avviare l’oscillatore secondario ed ho dovuto innalzare le C12 e C13 a 33pF. Per cui se utilizzate il PIC32MX e la demo vi si blocca alla fine (display vuoto e l’orologio non viene mostrato), provate a sostituire C12 e C13 con valori di capacità più elevati.

Questo è un video della demo:

ORbit16™

ORbit16™ è un progetto a supporto di Settorezero.com. I codici sorgente, le librerie, la documentazione e tutto il resto vengono rilasciati soltanto a chi contribuisce, acquistando una ORbit16™ in qualsiasi versione (anche il solo PCB). Siamo stati costretti a ricorrere a questo sistema perchè si diffonde a macchia d’olio la brutta abitudine di copiare i progetti altrui per partecipare a concorsi o per ripubblicarli su siti a punteggio, e settorezero.com è contrario a queste pratiche scorrette, messe in pratica da siti che lucrano sul lavoro altrui. Se vuoi sostenere settorezero.com ci sono anche altri modi, come il partecipare con tuo personale progetto (non copiato da nessuno o utilizzando materiali dichiarati come open source/liberamente utilizzabili citando l’autore originale o materiali prelevati qui da settorezero.com). Se sei interessato ad ottenere una ORbit16™, leggi qui come fare.

Links

Se questo articolo ti è piaciuto, condividilo su un social:
Se l'articolo ti è piaciuto o ti è stato utile, potresti dedicare un minuto a leggere questa pagina, dove ho elencato alcune cose che potrebbero farmi contento? Grazie :)