Forum: Mikrocontroller und Digitale Elektronik SSD1322 OLED ansteuern


von Janis E. (janis_e)


Lesenswert?

Hallo,

ich möchte mit einem FPGA Board (MachXO2 Breakout Board) ein 256x64 OLED 
mit SSD1322 Controller ansteuern. Da es (vermutlich) kein FPGA Problem 
ist, habe ich mich für dieses Forum entschieden.

Zuerst habe ich versucht über das Datenblatt 
(http://www.newhavendisplay.com/redirect.html?goto=www.newhavendisplay.com%2Fspecs%2FNHD-2.8-25664UMY3.pdf&action=url) 
eine eigene Ansteuerung zu entwerfen. Dazu habe ich das Display mit 
Masse, 3.3V Versorgungsspannung vom FPGA (mit Pufferkondensator), und 
die I/O Pins für das parallele 6800 Interface direkt mit entsprechenden 
FPGA Pins verbunden.

Mein eigener Entwurf für eine Verilog FSM zur Ansteuerung hat leider 
kein Ergebnis erzielt. Es ist einfach gar nichts passiert (in der 
Simulation sah die Ansteuerung für mich in Ordnung aus). Nun scheint 
aber vor allem die Initialisierung des SSD1322 ziemlich kniffelig zu 
sein. Daher habe ich den vom Hersteller bereitgestellten Demo C Code 
(https://www.newhavendisplay.com/app_notes/OLED_25664.txt) verwendet. 
Einziges Problem für mich waren die Sleep Routinen. "OLED_uDelay(x)" 
wird wahrscheinlich für eine Verzögerung von x Mikrosekunden sorgen, 
aber was ist mit "OLED_Delay(x)" (ohne Einheit)? Da ich im Datenblatt 
weder vom Hersteller noch vom Controller diesen Wert gefunden habe, habe 
ich ebenfalls Mikrosekunden angenommen.

War das vielleicht falsch?

In meiner main Methode rufe ich nun nacheinander die Funktionen 
OLED_Init_25664() und Checkerboard_25664() auf.

Für die 8 Datenleitungen und die 4 benötigten Steuersignale 
(/RES,/CS,DC,E) habe ich zwei GPIOs konfiguriert, und im Simulator 
getestet. Die entsprechenden Funktionen im Democode habe ich 
umgeschrieben. Wenn ich nun den Code ausführe, leuchtet für den 
Bruchteil einer Sekunde eine horizontale Linie auf, manchmal auch 2-3.

An dieser Stelle komme ich nun nicht weiter. Die Verbindungen zwischen 
den Pins des FPGAs und dem Display habe ich überprüft. Die Output Pins 
des FPGAs sind als IO Type LVCMOS33 konfiguriert, das müsste also auch 
stimmen. Der 3.3V Spannungswandler des FPGA Boards liefert laut 
Datenblatt bis zu 1A. Testweise habe ich neben meinem USB Hub mit 
externer Stromversorgung auch ein starkes USB Netzteil (funktioniert mit 
Raspberry Pi) verwendet, aber das Resultat war das gleiche.

Habt ihr eine Idee wie ich ohne Oszilloskop und Logic Analyzer das 
Problem weiter eingrenzen kann?

Danke im Voraus!

von hp-freund (Gast)


Lesenswert?

Ein Delay ohne Einheit ist wahrscheinlich im ms gemeint.

Hier:
http://docs-europe.electrocomponents.com/webdocs/0d2c/0900766b80d2c7d9.pdf

ist das Timing angegeben.

Hast Du auch den Punkt 10 - Power-On Sequence beachtet?

von Janis E. (janis_e)


Lesenswert?

hp-freund schrieb:
> Ein Delay ohne Einheit ist wahrscheinlich im ms gemeint.

Das wären dann 10s Delay.. Ich habe jetzt einmal versucht es aus dem 
Datenblatt herauszulesen, aber genau dieser Wert (10000) taucht an 
dieser Stelle in keiner Möglichkeit auf (unabhängig von der Einheit). Da 
es aber nur einen Aufruf gibt, der direkt nach dem Reset auftritt, ist 
es weniger kritisch.

hp-freund schrieb:
> Hier:
> http://docs-europe.electrocomponents.com/webdocs/0d2c/0900766b80d2c7d9.pdf

Danke für den Link! Ich habe mir auch bereits schon andere Datenblätter 
für den Controller angesehen. Was mich irritiert ist die 
unterschiedliche Initialisierung. Laut Datenblatt muss direkt nach dem 
Reset der Befehl 0xAF (Display ON) gesendet werden. Im Beispielcode vom 
Hersteller wird dies viel später gemacht (dort wird zunächst "Unlock 
Commands" und "Display OFF" aufgerufen). Was stimmt denn nun?

von Frank M. (frank_m35)


Lesenswert?

Das Display findet sich bei vielen Herstellern z.B. die von mir 
verwendete 3.2" Version von Densitron als DD-25664YW-4A oder von 
Eastrising als ER-OLED032-1Y. Beide sind identisch. Beide verwenden auch 
den SSD1322 Controller. Beide Displays gibt es auch in der 2.8" 
Variante. Somit denke ich ist zwischen Densitron, Eastrising und 
Newhavendisplay kein Unterschied am Panel selbst.

Günstig sind sie eben von Eastrising:
http://www.buydisplay.com/default/oled-display/256x64-dot-matrix-2-8-oled-display-module-with-datasheet-price-pinout-arduino-serial-spi-interface-from-china-manufacturer-supplier
http://www.buydisplay.com/default/oled-display/256x64-dot-matrix-3-2-oled-display-module-with-datasheet-price-pinout-arduino-serial-spi-interface-from-china-manufacturer-supplier

Auf dieser Seite findest du auch ein Series Manual, was verdammte 
Ähnlichkeiten zu dem von Densitron aufweist.

Wie dem auch sei, das Datenblatt finde ich ausführlicher als dein 
verlinktes. Es hat die Einschalt und Ausschaltsequenz sowie eine 
ausführliche Intialisierungsroutine abgebildet, welche ich auch 
erfolgreich so verwende:
(für einen PIC24F, ansteurung über das parallele Interface)
1
/*********************************************************************
2
* Function:  void ResetDevice()
3
* Overview: resets LCD, initializes PMP
4
* Input: none
5
* Output: none
6
********************************************************************/
7
void ResetDevice(void)
8
{
9
  // Initialize the device
10
  // RES=0, Delay, RES=1 and init of PMP
11
  DriverInterfaceInit();
12
13
  DisplayEnable();      // Pull CS# LOW
14
15
    // Command Unlock
16
    Write_Command(0xFD);
17
    DeviceWrite(0x12);
18
19
    // Setup Display
20
    Write_Command(0xAE);             // turn off the display (AF=ON, AE=OFF)
21
22
    // Set Display Clock Divide Ratio/Oscillator Frequency
23
    Write_Command(0xB3);
24
    DeviceWrite(0x91);  // Set Clock as 135 Frames/Sec
25
26
    //Set Multiplex Ratio
27
    Write_Command(0xCA);
28
    DeviceWrite(0x3F);  // 1/64 Duty (0x0F~0x5F)
29
30
    // Set Display Offset
31
    Write_Command(0xA2);
32
    DeviceWrite(0x00);
33
    //DeviceWrite(0x4C);
34
35
    // Set Display Start Line
36
    Write_Command(0xA1);
37
    DeviceWrite(0x00);  // Set Mapping RAM Display Start Line (0x00~0x5F)
38
    
39
    // Set Re-Map
40
    Write_Command(0xA0);
41
    DeviceWrite(0x06);  // 180 Degree rotated
42
    //DeviceWrite(0x14);    // 180 Degree rotated
43
    DeviceWrite(0x11);
44
45
    // Disable GPIO Pins Input
46
    Write_Command(0xB5);
47
    DeviceWrite(0x00);
48
49
    // Function selection
50
    Write_Command(0xAB);
51
    DeviceWrite(0x01);
52
53
    // Enable External VSL
54
    Write_Command(0xB4);
55
    DeviceWrite(0xA0);
56
    DeviceWrite(0xFD);
57
58
    // Set contrast current
59
    Write_Command(0xC1);
60
    DeviceWrite(0x9F);
61
62
    // Set Master Contrast Current Control
63
    Write_Command(0xC7);
64
    DeviceWrite(0x0F);
65
66
    // Select Default Linear Gray Scale Table
67
    DeviceWrite(0xB9);
68
69
    //  Set Phase Length
70
    Write_Command(0xB1);
71
    DeviceWrite(0xE2);
72
73
    // Enhance Driving Scheme Capability
74
    Write_Command(0xD1);
75
    DeviceWrite(0x82);
76
    DeviceWrite(0x20);
77
78
    // Set Pre-Charge Voltage
79
    Write_Command(0xBB);
80
    DeviceWrite(0x1F);
81
82
    // Set Second Pre-Charge Period
83
    Write_Command(0xB6);
84
    DeviceWrite(0x08);
85
86
    // Set VCOMH Deselect Level
87
    Write_Command(0xBE);
88
    DeviceWrite(0x07);
89
90
    // Set Display Mode
91
    Write_Command(0xA6);    // Normal Display
92
93
    // Exit partial device mode
94
    Write_Command(0xA9);
95
96
    // Clear Screen
97
    ClearDevice();
98
    UpdateDisplayNow();
99
    DisplayEnable();
100
101
    // Power Up Vcc
102
    LATGbits.LATG1 = 1; // OLED DC pump on
103
    DelayMs(100);
104
105
    // Set Display On  
106
    Write_Command(0xAF);
107
108
    DisplayDisable();
109
}

von Harry (Gast)


Lesenswert?

Ich hoffe du kannst mit Pascal was anfangen ?
So initialisiere ich das (OLED, 256x32, SSD1322-Controller)
1
Procedure Write_C(Daten:Byte);              // Write Command
2
  Begin
3
    Write_Port;
4
    Oled_RD:=1;
5
    Oled_CS:=0;
6
    Oled_D_C:=0;
7
    Oled_WR:=0;
8
    PortB:=Daten;                           //PB7 u. PB6  entspr.  D7 u. D6
9
    PortC:=Daten;                           //PC0 - PC5  entspr.   D0 - D5
10
    NOP; NOP;
11
    Oled_WR:=1;
12
    Oled_CS:=1;
13
  End Write_C;
14
15
16
Procedure Write_D(Daten:Byte);              // Write Data
17
  Begin
18
    //Schreibe_Port;
19
    Oled_RD:=1;
20
    Oled_CS:=0;
21
    Oled_D_C:=1;
22
    Oled_WR:=0;
23
    PortB:=Daten;                           //PB7 u. PB6  entspr.  D7 u. D6
24
    PortC:=Daten;                           //PC0 - PC5  entspr.   D0 - D5
25
    NOP; NOP;
26
    Oled_WR:=1;
27
    Oled_CS:=1;
28
  End Write_D;
29
30
31
Function Read_D:Byte;                       // Read Data
32
  Var  A,B:Byte;
33
  Begin
34
    Read_Port;
35
    Oled_WR:=1;
36
    Oled_CS:=0;
37
    Oled_D_C:=1;
38
    Oled_RD:=0;
39
    NOP; NOP;
40
    A:=PINB and %11000000;                  //PB7 u. PB6  entspr.  D7 u. D6
41
    B:=PINC and %00111111;                  //PC0 - PC5  entspr.   D0 - D5
42
    Oled_RD:=1;
43
    Oled_CS:=1;
44
    Return(B or A);
45
  End Read_D;
46
47
48
Procedure Clear_OLED_RAM;
49
  Var A:Word;
50
  Begin
51
    Write_C($15);   //Set Column Adress  , sichtbarer Bereich 28 - 91
52
    Write_D(28);
53
    Write_D(91);
54
    Write_C($75);   //Set Row Adress  , sichtbarer Bereich 0-63
55
    Write_D(0);
56
    Write_D(63);
57
    Write_C($5C);   //Befehl Write OLED RAM bleibt aktiv bis ein nächstes Kommando kommt
58
    NOP; NOP; NOP; NOP;
59
    For A:= 1 to 8192 do
60
      Write_D($00); //ein Byte repräsentiert 2 Pixel (Grayscale) ((256 / 2)* 64)
61
      EndFor;
62
  End Clear_OLED_RAM;
63
64
65
Procedure Init_OLED;
66
  Begin
67
    MDelay(50);
68
    Oled_RST:=0;
69
    MDelay(50);
70
    Oled_RST:=1;
71
    MDelay(50);
72
    Write_C($FD);        //Display Lock  einmalig,damit das OLED Commandos empfängt
73
    Write_D($12);
74
    Write_C($AE);        //Display OFF  , Displaycontroller aktiv,Panel inaktiv
75
    Write_C($B3);        //Display Clock , interner Osc und Divisor , bleibt unverändert
76
    Write_D(%10010001);
77
    Write_C($CA);        //Set Multiplex , entspricht der Pixelhöhe des Display's
78
    Write_D(63);         //Höhe - 1    ,  64 Pixel
79
    Write_C($A2);        //Set Offset , beginne bei Reihe 0
80
    Write_D(0);
81
    Write_C($A1);        //Set Startline , beginne bei Reihe 0
82
    Write_D(0);
83
    Write_C($A0);        //Set Remasp
84
    Write_D(%00000110);  //0b00000110  verkehrt ,0b00010100 normal(Displayanschluß unten)
85
    Write_D(%00010001);
86
    Write_C($B5);        //Set GPIO  , keine weitere Bedeutung da diese Pin's nicht rausgeführt
87
    Write_D(0);
88
    Write_C($AB);        //Set Funktion , bleibt unverändert
89
    Write_D($01);
90
    Write_C($B4);        //External VSL , bleibt unverändert
91
    Write_D($A0);
92
    Write_D($FD);
93
    Write_C($C1);        //Set Contrast Current , Genereller Kontrast , bleibt unverändert
94
    Write_D($9F);
95
    Write_C($C7);        //Set Master Contrast , Hier ist eine Helligkeitsanpassung möglich
96
    Write_D(10);         // 0-14  Empfehlung 9-10 oder weniger , je mehr umso weniger LifeTime !!!
97
    Write_C($B9);        //Set Default Gray Scale , bleibt unverändert
98
    Write_C($B1);        //Set pre & dis_charge , bleibt unverändert
99
    Write_D($F0);
100
    Write_C($D1);        //Enhance Driving Scheme , bleibt unverändert
101
    Write_D($82);
102
    Write_D($20);
103
    Write_C($BB);        //Set pre-charge Voltage
104
    Write_D(31);
105
    Write_C($B6);        //Set Second Pre-charge Period
106
    Write_D($08);
107
    Write_C($BE);        //Set VCOMH
108
    Write_D(7);
109
    Write_C($A6);        //Display normel  , "0xa7" Display reverse
110
    Clear_OLED_Ram;
111
    MDelay(50);
112
    VPP_EN:=1;
113
    MDelay(50);
114
    Write_C($AF);        //Display ON  , Displaycontroller aktiv,Panel aktiv
115
  End Init_OLED;

von Info (Gast)


Lesenswert?

Frank M. schrieb:
> Somit denke ich ist zwischen Densitron, Eastrising und
> Newhavendisplay kein Unterschied am Panel selbst.

Ich habe ein 256x64 Modul via Aliexpress gekauft (auch $30, incl. 
Versand), das identisch zu den Eastrising-Modulen aussieht 
(Bestückungsdruck: "TW56640320B03") und auf der Salomon Systech 
SSDSSD1322UR "Flex assembly" aufbaut.

Es ist für 4-wire SPI konfiguriert und ich habe es mit angepasstem Code 
von https://github.com/MartyMacGyver/OLED_SSD1322 auf einem "Blue Pill" 
STM32F103 board mit STM32duino grundsätzlich zum Laufen gebracht.

Die Initialisierung scheint auf den ersten Blick mit der von Eastrising 
übereinzustimmen.
Aber: offenbar hat mein Display einen Column-Offset von 28 (genutzt mit 
"Set Column Address", offset=startline=0).

Frage: habt ihr diesen Offset auch oder ist bei mir evtl. eine 
Mapping-Einstellung falsch? Oder ist bei der Fertigung etwas verrutscht?


Ansonsten bin ich kein Freund vom Datenblatt des Controllers.
Es steht nirgends explizit, dass ein write-Befehl bzw. eine Column zwei 
Bytes braucht und erst dann ins Display-Ram schreibt.
Es gibt nur Hinweise, wie bei "Set Row Address": "After finishing 
read/write four pixels of data, the column address is increased 
automatically by 1 to access the next RAM
location  for  next  read/write  operation".
Oder bei GDDRAM Structure: auf den zweiten Blick sieht man, dass eine 
Column aus vier Segmenten besteht. "Data Bus to RAM Mapping" zeigt auch 
zwei Bytes. Naja.

von Stefan F. (Gast)


Lesenswert?

Das Datenblatt vom SSD1306 ist genau so ätzend. Dafür habe ich letztes 
Wochenende einen Treiber geschrieben (aus Spaß am Machen, nicht dass es 
wirklich nötig gewesen wäre).

Die meisten Treiber, die ich im Internet gefunden habe, haben jedes 
Kommando einzeln als separate I²C Transaktion gesendet. Ich habe aber 
gemerkt, dass man beliebig viele Kommandos hintereinander in einem 
Rutsch senden kann.

Im Gegensatz zum HD44780 kann man bei den SSD13xx Controllern die 
Kommandos offensichtlich ohne Delay direkt hintereinander senden.

Was die Reihenfolge der Initialisierung angeht: Ich habe das Gefühl, 
dass die Kommandos (fast) in beliebiger Reihenfolge gesendet werden 
können. Jede Implementierung macht es anders und keine, die ich gesehen 
habe, hält sich exakt an das Datenblatt. Es würde mich nicht wundern, 
wenn die empfohlene Sequenz in jeder Version des Datenblattes anders 
aussieht. Typisch chinesisch.

> habt ihr diesen Offset auch?

Beim 128 Pixel breiten Displays mit SH1106 (welcher dem SSD13xx zu 99% 
gleicht) gibt es auch einen Offset. Da hat das RAM 132 Spalten, das 
Display aber nur 128. Der Offset ist dort 2 (also zentriert).

von Info (Gast)


Lesenswert?

Mhh, zentriert?

Controller: 480 pixels/nibbles == 240 Bytes == 120 columns (Achtung, in 
GDRAM-Tabelle ist 77 Hex == 119)
Display: 256 pixels/nibbles == 128 Bytes == 64 columns

(120-64)/2 = 28

Tada!

Als 0x1C auch in http://www.newhavendisplay.com/app_notes/OLED_25664.txt 
als magic number.

Meine Quelle hat es wohl einfach verpeilt:
> // Still figuring these out...

Rätsel gelöst - danke für den Hinweis!

von Stefan F. (Gast)


Lesenswert?

> Rätsel gelöst - danke für den Hinweis!

Na, da hatte ich ja gut geraten.

von Info (Gast)


Lesenswert?

Ja! Gleich nochmal:

Gibt es ein Mittel oder eine Einstellung gegen Streifen, d.h. hellere 
Pixel, die offenbar entstehen, wenn Zeilen auch eine nennenswerte Zahl 
schwarzer Pixel hat als die umliegenden? Als würde der Zeilentreiber 
dann zuviel Strom ausgeben. Oder aber, in alle anderen Zeilen schafft 
der Zeilentreiber nicht alle Pixel und sie erscheinen daher dunkler.

...

Ok, Initialisierung angepasst (Densitron/Newhaven) und es ist deutlich 
besser, aber dennoch sichtbar.

von Stefan F. (Gast)


Lesenswert?

Ich kann nur sagen, dass mein OLED Display mit dem anderen SSD1306 keine 
Streifen macht.

Schau mal im Datenblatt 
(https://www.crystalfontz.com/controllers/SolomonSystech/SSD1322/427/) 
nach dem Stichwort "contrast".

Die LEDs werden mit einem konstanten Strom angesteuert, dessen Maximum 
durch einen Widerstand außerhalb des IC bestimmt wird und von 0 bis max 
per Befehl einstellbar ist.

Vielleicht ist bei Dir die höhere Spannungsversorgung für die LEDs (7V?) 
instabil. Hast du eine Charge-Pump, dann ist diese vielleicht 
überlastet, oder sie liefert wegen falschen Kondensatoren/Spulen keine 
konstante Spannung.

In diesem Fall könnte es schon genügen, die Helligkeit zu verringern. 
Das wäre auch für die Lebensdauer des Displays von Vorteil.

von Info (Gast)


Lesenswert?

Danke für die Hinweise.
Der kleine SOT23-5 auf dem "generic STM32" schafft die 3.3 V Versorgung, 
wenn auch mit einem delta-T von 35 K.

Die generierten Spannungen scheinen aber auch alle zu passen (13.6 V für 
die LEDs).

Helligkeit ist schon reduziert.

Man könnte ein Testmuster generieren und die Einstellungen durchtesten 
... oder den Effekt erstmal ignorieren. Ist nicht so schlimm.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.