Display OLED RGB 65k con controller SSD1332

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à! 🙂

4 Risposte a “Display OLED RGB 65k con controller SSD1332”

  1. 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

    1. 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. 🙂

I commenti sono chiusi.