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!
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?
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?
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 | }
|
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; |
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.
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).
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!
> Rätsel gelöst - danke für den Hinweis!
Na, da hatte ich ja gut geraten.
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.
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.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.