Con il progetto cubex ho avuto modo di provare un piccolo display OLED monocromatico (blu) da circa un pollice di diagonale.
In questi giorni mi è arrivato un nuovo display OLED sempre della Solomon Systech ma questa volta a 65mila colori. Sempre di piccole dimensioni (diagonale da un pollice) è un RGB96x64 pixels. Che ne dite di provarlo? 😀
Dopo una prima lettura del datasheet del SSD1332 ho notato la somiglianza con il controller del vecchio OLED SH1101A usato nel progetto cubex, guardando lo schema di pinout dell’oled infatti mi risulta tutto molto famigliare:
Si possono notare questi pin:
- Vcc: per fornire l’alta tensione (7-18V) al pannello dell’OLED
- Vcomh: visto che la tensione per le linee COM del display è generata internamente, a questo pin basta collegare un condensatore da 4,7uF per stabilizzare la tensione.
- D7-D0: questi 8pins sono le 8 linee bidirezionali del bus di comunicazione con il microcontrollore
- E: il pin di enable nella comunicazione parallela motorola6800 oppure pin READ nella comunicazione parallela intel8080. Se viene utilizzata una comunicazione seriale SPI questo pin deve essere portato a massa.
- RW: nella comunicazione parallela motorola6800 il pin è utilizzato per selezionare un’operazione di lettura o scrittura, mentre nella comunicazione intel8080 è utilizzato come pin WRITE. Se viene utilizzata una comunicazione seriale SPI questo pin deve essere portato a massa.
- DC: in tutti i tipi di comunicazione questo pin è utilizzato per controllare l’invio di un comando oppure di un dato al display OLED.
- RES: è il pin per resettare l’oled (attivo basso).
- CS: è il pin ChipSelect per selezionare l’oled prima di iniziare una comunicazione con lo stesso.
- IREF: è il pin per il riferimento di corrente dei vari segmenti dell’oled, in base alla tensione di alimentazione bisogna porre una resistenza opportuna per limitare la corrente a circa 10uA
- BS2-BS1: sono i pins per poter scegliere il metodo di comunicazione con il microcontrollore (motorola6800, intel8080 oppure seriale SPI)
- Vdd: input della bassa tensione per gestire la logica del display oled (2.4 – 3.5 V).
- VP_C-VP_B-VP_A-VBref-RESE-FB-VDDB-GDR: tutti questi pin sono relativi al convertitore di tensione DC-DC interno. Visto che personalmente fornisco la Vcc tramite integrato apposito (TC1240A), questi pin vanno lasciati flottanti.
- Vss: è il collegamento a massa dell’oled.
Ho scelto la comunicazione parallela rispetto alla comunicazione seriale SPI perchè mi permette di effettuare operazioni della lettura della RAM interna del display anche se necessita di ben 8 linee dati aggiuntive rispetto alla comunicazione SPI.
Direi che si può partire con la progettazione usando il nostro amato PIC32MX, un piccolo connettore microUSB per la comunicazione con il PC, un socket per scheda microSD in previsione di leggere/salvare dei dati ed il classico LDO microchip MCP1700T per fornire i 3,3V a tutti i componenti partendo dai 5V della connessione USB.
Ecco il master:
Si può iniziare la fotoincisione:
Ed ecco il risultato finale:
Mentre qui di seguito potete vedere il PCB quasi al completo, manca solamente l’OLED:
Ora prima di collegare l’OLED sarà meglio concentrarsi sul software! Dobbiamo preparare ed istruire il pic per poter dialogare correttamente con l’OLED tramite interfaccia parallela.
Per prima cosa ho creato un file SSD1332.h con la definizione delle porte utilizzate dal pic:
#include
#ifndef OLEDSSD1332_H
#define OLEDSSD1332_H
//definizioni collegamenti OLED
#define OLEDVCCport IOPORT_F
#define OLEDVCCbit BIT_1
#define OLEDVcc LATFbits.LATF1 //OLED VCC (7-18V)
#define OLEDVcc_direction TRISFbits.TRISF1
#define OLEDVDDport IOPORT_B
#define OLEDVDDbit BIT_3
#define OLEDVdd LATBbits.LATB3 //OLED VDD (2.4-3.5V)
#define OLEDVdd_direction TRISBbits.TRISB3
#define OLED_D0port IOPORT_E
#define OLED_D0bit BIT_7
#define OLED_D0 LATEbits.LATE7 //OLED D0
#define OLED_D0in PORTEbits.RE7
#define OLED_D0_direction TRISEbits.TRISE7
#define OLED_D1port IOPORT_E
#define OLED_D1bit BIT_6
#define OLED_D1 LATEbits.LATE6 //OLED D1
#define OLED_D1in PORTEbits.RE6
#define OLED_D1_direction TRISEbits.TRISE6
#define OLED_D2port IOPORT_E
#define OLED_D2bit BIT_5
#define OLED_D2 LATEbits.LATE5 //OLED D2
#define OLED_D2in PORTEbits.RE5
#define OLED_D2_direction TRISEbits.TRISE5
#define OLED_D3port IOPORT_E
#define OLED_D3bit BIT_4
#define OLED_D3 LATEbits.LATE4 //OLED D3
#define OLED_D3in PORTEbits.RE4
#define OLED_D3_direction TRISEbits.TRISE4
#define OLED_D4port IOPORT_E
#define OLED_D4bit BIT_3
#define OLED_D4 LATEbits.LATE3 //OLED D4
#define OLED_D4in PORTEbits.RE3
#define OLED_D4_direction TRISEbits.TRISE3
#define OLED_D5port IOPORT_E
#define OLED_D5bit BIT_2
#define OLED_D5 LATEbits.LATE2 //OLED D5
#define OLED_D5in PORTEbits.RE2
#define OLED_D5_direction TRISEbits.TRISE2
#define OLED_D6port IOPORT_E
#define OLED_D6bit BIT_1
#define OLED_D6 LATEbits.LATE1 //OLED D6
#define OLED_D6in PORTEbits.RE1
#define OLED_D6_direction TRISEbits.TRISE1
#define OLED_D7port IOPORT_E
#define OLED_D7bit BIT_0
#define OLED_D7 LATEbits.LATE0 //OLED D7
#define OLED_D7in PORTEbits.RE0
#define OLED_D7_direction TRISEbits.TRISE0
#define OLEDEport IOPORT_G
#define OLEDEbit BIT_6
#define OLEDe LATGbits.LATG6 //OLED E
#define OLEDe_direction TRISGbits.TRISG6
#define OLEDRWport IOPORT_G
#define OLEDRWbit BIT_7
#define OLEDrw LATGbits.LATG7 //OLED RW
#define OLEDrw_direction TRISGbits.TRISG7
#define OLEDDCport IOPORT_G
#define OLEDDCbit BIT_8
#define OLEDdc LATGbits.LATG8 //OLED DC
#define OLEDdc_direction TRISGbits.TRISG8
#define OLEDRESport IOPORT_B
#define OLEDRESbit BIT_5
#define OLEDres LATBbits.LATB5 //OLED reset
#define OLEDres_direction TRISBbits.TRISB5
#define OLEDCSport IOPORT_B
#define OLEDCSbit BIT_4
#define OLEDcs LATBbits.LATB4 //OLED CS
#define OLEDcs_direction TRISBbits.TRISB4
#endif
mentre nel file SSD1332.c ho iniziato a scrivere qualche funzione per poter inviare un comando da 8bit all’oled:
/****************************************************************************\
| Funzione: oled_wait()
| Descrizione: delay generico per la comunicazione parallela con l'OLED
\****************************************************************************/
void oled_wait()
{
//delay_us(1);
//asm("nop");
}
/****************************************************************************\
| Funzione: oled_init
| Descrizione: configura i pin input/ouput per la connessione all'OLED
\****************************************************************************/
void oled_init()
{
//Alimentazione oled come output spenta
OLEDVcc_direction=0;
PORTSetPinsDigitalOut(OLEDVCCport,OLEDVCCbit);
OLEDVcc=1; //Vcc spenta (activeLow)
OLEDVdd_direction=0;
PORTSetPinsDigitalOut(OLEDVDDport,OLEDVDDbit);
OLEDVdd=0; //Vdd spenta 3.3V
//configuro i pin data D0..D7 come uscita
oled_PAR_setPortOUT();
OLED_D0=0;
OLED_D1=0;
OLED_D2=0;
OLED_D3=0;
OLED_D4=0;
OLED_D5=0;
OLED_D6=0;
OLED_D7=0;
//configuro i pin di interfaccia
OLEDe_direction=0;
PORTSetPinsDigitalOut(OLEDEport,OLEDEbit);
OLEDe=0;
OLEDrw_direction=0;
PORTSetPinsDigitalOut(OLEDRWport,OLEDRWbit);
OLEDrw=0;
OLEDdc_direction=0;
PORTSetPinsDigitalOut(OLEDDCport,OLEDDCbit);
OLEDdc=0;
OLEDres_direction=0;
PORTSetPinsDigitalOut(OLEDRESport,OLEDRESbit);
OLEDres=1; //reset alto (activeLow)
OLEDcs_direction=0;
PORTSetPinsDigitalOut(OLEDCSport,OLEDCSbit);
OLEDcs=1; //chipSelect altro (activeLow)
}
/****************************************************************************\
| Funzione: oled_PAR_setPortOUT
| Descrizione: imposta i pin D0..D7 come output
\****************************************************************************/
void oled_PAR_setPortOUT()
{
OLED_D0_direction=0;
PORTSetPinsDigitalOut(OLED_D0port,OLED_D0bit);
OLED_D1_direction=0;
PORTSetPinsDigitalOut(OLED_D1port,OLED_D1bit);
OLED_D2_direction=0;
PORTSetPinsDigitalOut(OLED_D2port,OLED_D2bit);
OLED_D3_direction=0;
PORTSetPinsDigitalOut(OLED_D3port,OLED_D3bit);
OLED_D4_direction=0;
PORTSetPinsDigitalOut(OLED_D4port,OLED_D4bit);
OLED_D5_direction=0;
PORTSetPinsDigitalOut(OLED_D5port,OLED_D5bit);
OLED_D6_direction=0;
PORTSetPinsDigitalOut(OLED_D6port,OLED_D6bit);
OLED_D7_direction=0;
PORTSetPinsDigitalOut(OLED_D7port,OLED_D7bit);
}
/****************************************************************************\
| Funzione: oled_PAR_setPortIN()
| Descrizione: imposta i pin D0..D7 come input
\****************************************************************************/
void oled_PAR_setPortIN()
{
OLED_D0_direction=1;
PORTSetPinsDigitalIn(OLED_D0port,OLED_D0bit);
OLED_D1_direction=1;
PORTSetPinsDigitalIn(OLED_D1port,OLED_D1bit);
OLED_D2_direction=1;
PORTSetPinsDigitalIn(OLED_D2port,OLED_D2bit);
OLED_D3_direction=1;
PORTSetPinsDigitalIn(OLED_D3port,OLED_D3bit);
OLED_D4_direction=1;
PORTSetPinsDigitalIn(OLED_D4port,OLED_D4bit);
OLED_D5_direction=1;
PORTSetPinsDigitalIn(OLED_D5port,OLED_D5bit);
OLED_D6_direction=1;
PORTSetPinsDigitalIn(OLED_D6port,OLED_D6bit);
OLED_D7_direction=1;
PORTSetPinsDigitalIn(OLED_D7port,OLED_D7bit);
}
/****************************************************************************\
| Funzione: oled_PAR_setByte
| Descrizione: scrive 8bit sulla linea parallela
\****************************************************************************/
void oled_PAR_setByte(unsigned char cmd)
{
OLED_D0=cmd&0x01; cmd>>=1;
OLED_D1=cmd&0x01; cmd>>=1;
OLED_D2=cmd&0x01; cmd>>=1;
OLED_D3=cmd&0x01; cmd>>=1;
OLED_D4=cmd&0x01; cmd>>=1;
OLED_D5=cmd&0x01; cmd>>=1;
OLED_D6=cmd&0x01; cmd>>=1;
OLED_D7=cmd&0x01;
}
/****************************************************************************\
| Funzione: oled_PAR_getByte
| Descrizione: legge 8bit sulla linea parallela
\****************************************************************************/
unsigned char oled_PAR_getByte()
{
unsigned char dato=0;
if(OLED_D0in)dato++; dato<
con la funzione oled_sendCMD() possiamo creare tutte le altre funzioni che serviranno per impostare tutti i vari parametri dell’oled. Seguendo il datasheet da pagina 26 possiamo facilmente implementarle tutte! 🙂
Un esempio è questa per impostare la configurazione principale dell’alimentazione Vcc esterna (7-18V), mentre VCOMH e VP generate internamente:
void oled_setMasterConfiguration(unsigned char value)
{
unsigned char cmd[]={0xAD,value};
oled_sendCMD(cmd,2);
}
ora abbiamo tutto il necessario per poter scrivere una funzione che inizializzi le porte del pic ed esegua l’inizializzazione dell’oled:
/****************************************************************************\
| Funzione: oled_powerON
| Descrizione: accende l'oled ed inizializza i vari registri (necessita del comando
| oled_init() prima di essere invocata.
\****************************************************************************/
void oled_powerON()
{
OLEDe=0; //e a zero (activeHigh)
OLEDcs=1; //chipSelect ad uno (activeLow)
OLEDres=1; //reset alto (activeLOW)
//Inizio il processo di accensione dell'Oled
OLEDVdd=1; //attivo Vdd (3,3V)
delay_ms(100); //aspetto che si stabilizzi la Vdd
OLEDres=0;
delay_us(5); //impulso di reset negativo di almeno 3us
OLEDres=1;
OLEDVcc=0; //attivo Vcc (8-10V)
delay_ms(100); //aspetto che si stabilizzi la Vcc
//Invio i comandi per inizializzare il display
//set master configuration
//vcc esterna - vcomh interna - VP interna
oled_setMasterConfiguration(0x8E);
//set multiplex ratio
oled_setMultiplexRatio(0x3F); //64pixels disponibili
//SET remap e data format
oled_setReMapDataFormat(0x70); //65k e direzione
//contrasto colore A
oled_setContrastRED(0x80); //ef
//contrasto colore B
oled_setContrastGREEN(0x80); //11
//contrasto colore C
oled_setContrastBLUE(0x80); //48
oled_setMasterCurrentControl(0x0F); //0-16
oled_setVPAlevel(0x00);
oled_setVPBlevel(0x40);
oled_setVPClevel(0x7F);
oled_enableLinearGreyScaleTable();
oled_setVCOMH(0x3F);
oled_phasePeriodAdj(0x0F,0x01);
oled_setClockDividerFreq(0xF0);
oled_setDisplayONOFF(1); //DISPLAY ON
}
Penso che sia arrivato il momento di saldare l’OLED e provare a dare tensione! 😀
Ecco il risultato della prima accensione:
Leggendo il datasheet mi sono inoltre accorto che questo controller possiede anche delle funzionalità grafiche attivabili tramite comandi. Ad esempio permette la creazione di linee, rettangoli vuoti o colorati, permette di effettuare la copia di una porzione di schermo, oscurare una determinata zona, etc…
Usando quindi sempre la nostra funzione oled_sendCMD() possiamo implementare anche queste funzionalità, un esempio potrebbe essere questo per la creazione di una linea:
/****************************************************************************\
| Funzione: oled_drawLine
| Descrizione: disegna una linea sull'oled
\****************************************************************************/
void oled_drawLine(unsigned char xStart,unsigned char yStart,unsigned char xStop,unsigned char yStop,unsigned char red,unsigned char green,unsigned char blue)
{
unsigned char cmd[]={0x21,
xStart&0x7F,
yStart&0x3F,
xStop&0x7F,
yStop&0x3F,
(blue&0x1F)<<1,
green&0x3F,
(red&0x1F)<<1
};
oled_sendCMD(cmd,8);
}
Nel video seguente potete vedere il software lato pc che invia le coordinate per disegnare la linea e per pochi secondi potrete vedere una linea gialla in mezzo allo schermo. Successivamente avvio un ciclo per visualizzare dei colori random a tutto schermo:
Ora il prossimo passo sarà ricontrollare un po’ il codice, ottimizzarlo un po’ e tentare di eseguire qualche operazione più complessa. Visualizzare qualche testo? un’immagine? un’animazione? un video?
Aggiornerò questo articolo appena ci saranno novità! 🙂
Hi
I would buy such a board
Actually It’s not available 🙂
hello dear Alberto
you have a nice site,congratulation and thanks for these information you’r giving us.
it seems that the c code on top is not complete,would you please give me your complete ssd1332 library,i need it so much.and thanks for your help
best regard
hey,
I’m sorry, but the code in this page is the most up to date code that I have. I didn’t had enough free time to finish it.
Thanks for your visit tho. 🙂