Forum: Mikrocontroller und Digitale Elektronik Problem mit ssd1306 I²C-OLED-Display


von J. T. (chaoskind)


Lesenswert?

MoinMoin,

ich hab mir vor einiger Zeit so ein Display:
Hm der Banggoodlink wird als Spam identifiziert. Es ist so ein 0.91Inch 
128*32 Pixel OLED-Display mit SSD1306 Controller.

bestellt. Ich weiß nicht mehr genau woher, aber rein optisch ist es 
genau dieses.

Ich verwende ein NUCLEO-L053R8 und SW4STM32 mit MXCube. Ich habe quasi 
null Erfahrung mit I²C und HAL, aber wollte mich endlich mal ein wenig 
dareinfuchsen.

Ich hab mit Cube ein neues Projekt erstellt, die I²C-Adresse vom Display 
aus dem Datenblatt angegeben und eine Übertragung versucht. Bekam aber 
kein Ack. Mit der verdoppelten Adresse bekomme ich aber immerhin mal 
mein Ack. (um das read/write-Bit kümmert sich wohl die HAL_Lib)

Dann hab ich erstmal ganz unbedarft den Display_On-Befehl an die Adresse 
gesendet, und nichts hat sich getan. Also noch einen Blick ins 
Datenblatt geworfen. Da steht:
"5) After the transmission of the slave address, either the control byte 
or the data byte may be sent across
the SDA. A control byte mainly consists of Co and D/C# bits following by 
six “0” ‘s.
a. If the Co bit is set as logic “0”, the transmission of the following 
information will contain
data bytes only.
b. The D/C# bit determines the next data byte is acted as a command or a 
data. If the D/C# bit is
set to logic “0”, it defines the following data byte as a command. If 
the D/C# bit is set to
logic “1”, it defines the following data byte as a data which will be 
stored at the GDDRAM.
The GDDRAM column address pointer will be increased by one automatically 
after each
data write."

Und dem Diagramm darüber entnehme ich, dass ich erst die Adresse vom 
Display senden muss, dann ein Control-Byte und dann meine Daten.
Dieses Control-Byte setzt sich zusammen aus Co, D/C und 6 Nullen.

Aber wie ist dass denn nun mit diesem Co? Wenn es 0 ist, werden die 
folgenden Informationen als Daten betrachtet. Heißt das im Umkehrschluß, 
wenn ich einen Befehl übertragen will, muss es 1 sein? Aber egal ob ich 
das "Command-Byte" nun als 0b11000000 oder 0b01000000 definiere, es tut 
sich nichts.
1
#define Display_Adr        0x78
2
  #define Display_On      0xAF
3
  #define Display_Off      0xAE
4
  #define Display_Normal    0xA6
5
  #define Display_Inverse    0xA7
6
  #define Entire_Display_On  0xA4
7
  #define Entire_Display_Off  0xA5
8
  #define Data_Byte      0b00000000
9
  #define Command_Byte    0b01000000
10
11
  Send_Buffer[0] = Command_Byte;
12
  Send_Buffer[1] = Display_On;
13
  HAL_I2C_Master_Transmit(&hi2c1, Display_Adr, &Send_Buffer[0], 2, I2C_Timeout);
14
  Send_Buffer[1] = Display_Inverse;
15
  HAL_I2C_Master_Transmit(&hi2c1, Display_Adr, &Send_Buffer[0], 2, I2C_Timeout);
16
17
  Send_Buffer[0] = Data_Byte;
18
  Send_Buffer[1] = 0b10101010;
19
  HAL_I2C_Master_Transmit(&hi2c1, Display_Adr, &Send_Buffer[0], 2, I2C_Timeout);

Ich hab auch versucht, das Display zu invertieren, um etwas sehen zu 
können.. Aber das Display bleibt schwarz.

Hat jemand eine Idee, woran das liegen kann?

MfG Chaos

von Daniel Düsentrieb (Gast)


Lesenswert?

Du willst das Rad unbedingt neu erfinden? Wie du willst,
aber lass dir beim Erfinden wenigstens helfen.

Ich hab nicht die Energie dir das haarklein auseinander-
zulegen.

Heisser Tip: Spicken hilft!

https://github.com/afiskon/stm32-ssd1306

von Stefan F. (Gast)


Lesenswert?

Das Display benötigt eine umfangreiche Initialisierungs-Sequenz. Du 
kannst von meinem Quelltext abgucken: 
http://stefanfrings.de/esp8266/WIFI-Kit-8-OLED.zip

von J. T. (chaoskind)


Lesenswert?

Danke euch erst mal für die Links

@Stefanus
Ich lese gerade über deine oled.h rüber, dabei ist mir glaube ich ein 
kleiner Fehler aufgefallen. Du schreibst :
" * The display is technically organized into "pages" which is a set of 
8 horizontal lines.
 * For a 128x32 display the memory contains 4 pages each of 128 bytes.
 * Each byte represents 8 pixels. Bit 0 is the top pixel, bit 7 is the 
bottom pixel."

Müsste das nicht "a set of 8 vertical lines" heißen? Horizontal ist doch 
waagerecht? Oder verwechsel ich da was? Evtl ist das ja einer Korrektur 
wert =).

Und des weiteren wird ein Reset-Pin erwähnt, mein Display hat jedoch nur 
die VCC-, GND-, SCL- und SDA_Pins herausgeführt. Ist der nötig und ich 
muss noch rumlöten? Wobei man ihn ja wegdefinieren kann, wenn ich deine 
oled.h soweit richtig verstanden hab.

Naja ich versuche mich mal weiter durch die oled.cpp zu lesen. Mal sehen 
ob ich das versteh, ich bin ja mehr nur son C-Grundlagiker, ich hoffe 
cpp is ähnlich genug :D

von spess53 (Gast)


Lesenswert?

Hi

>Ich lese gerade über deine oled.h rüber, dabei ist mir glaube ich ein
>kleiner Fehler aufgefallen. Du schreibst :
>" * The display is technically organized into "pages" which is a set of
>8 horizontal lines.
> * For a 128x32 display the memory contains 4 pages each of 128 bytes.
> * Each byte represents 8 pixels. Bit 0 is the top pixel, bit 7 is the
>bottom pixel."

Nö. Hast du dir mal im Dateblatt angesehen, wie die Pixel zugeordnet 
sind? Ein Byte im Bildspeicher representiert 8 senkrechte Pixel. Und 
eine Page besitzt 128 Bytes. Wenn du eine z.B. eine waagerechte Linie in 
der 4.Zeile darstellen willst, musst du alle Bits3 in der Page0 setzen.

MfG Spess

von J. T. (chaoskind)


Lesenswert?

@Stefan,

noch eine Frage zu deinem Code:

Du schreibst:
"    i2c_send((i2c_address << 1) & 0xFF); // address + write
    i2c_send(0x00); // command
    i2c_send(0xAE); // display off
"
Du sendest also 0x00 um dem Display zu sagen "jetzt kommt ein Befehl". 
Da versteh ich dann, wie im Eröffnungspost schon angedeutet, das 
Datenblatt nicht.

a.Wenn das Co-Bit logisch 0 ist, enthält die folgende Übertragung nur 
Data-Bytes.
b.Das D/C#-Bit bestimmt ob das nächste Data-Byte als Command oder Daten 
interpretiert wird. Ist es 0 sinds Commands, ist es 1 sind es Daten.

Eigentlich würde ich aus a schließen, dass das Co-Bit 1 sein muss, damit 
es halt Commands und nicht Daten sind. Aber es ist wohl das nur das 
D/C#-Bit, dass das bestimmt. Was macht dann das komische C0-Bit 
überhaupt? Braucht man das überhaupt?

Ansonsten denke ich aber, dass ich deine init soweit verstanden hab. 
Also nochmal herzlichen Dank dafür.

von J. T. (chaoskind)


Lesenswert?

spess53 schrieb:
> Nö. Hast du dir mal im Dateblatt angesehen, wie die Pixel zugeordnet
> sind? Ein Byte im Bildspeicher representiert 8 senkrechte Pixel. Und
> eine Page besitzt 128 Bytes. Wenn du eine z.B. eine waagerechte Linie in
> der 4.Zeile darstellen willst, musst du alle Bits3 in der Page0 setzen.
>
> MfG Spess

Da hab ich wohl irgendwie, senkrechten Bytes und waagerechten Pages 
durcheinander geworfen. Mir kam es beim überfliegen nur komisch vor, das 
erst von horizontal und dann von oberstem und unterstem "geredet" wurde. 
Zusammen mit deinem Hinweis und nochmal nachlesen ist mir das jetzt 
aufgegangen :D

von Harry L. (mysth)


Lesenswert?

Hier geschieht der Display-Refresh sogar via DMA im Hintergrund:
https://github.com/HarryLipphaus/DisplayKit

von J. T. (chaoskind)


Lesenswert?

Super, nun leuchten Pixel auf dem Display. Mit der 
Initialisierunssequenz von Stefanus ging es dann.

von Stefan F. (Gast)


Lesenswert?

J. T. schrieb:
> Müsste das nicht "a set of 8 vertical lines" heißen? Horizontal ist doch
> waagerecht?

Ja, das ist korrekt so. Die Bits des ersten Bytes sind auf dem Display 
dort:
1
0 . . . . . . . . . . . . . . . . . . . . . . . . \
2
1 . . . . . . . . . . . . . . . . . . . . . . . .  |
3
2 . . . . . . . . . . . . . . . . . . . . . . . .  |
4
3 . . . . . . . . . . . . . . . . . . . . . . . .  |  8 Reihen über die 
5
4 . . . . . . . . . . . . . . . . . . . . . . . .  |  ganze Breite sind 
6
5 . . . . . . . . . . . . . . . . . . . . . . . .  |  eine Page
7
6 . . . . . . . . . . . . . . . . . . . . . . . .  |
8
7 . . . . . . . . . . . . . . . . . . . . . . . . /
9
. . . . . . . . . . . . . . . . . . . . . . . . . \
10
. . . . . . . . . . . . . . . . . . . . . . . . .  |
11
. . . . . . . . . . . . . . . . . . . . . . . . .  |
12
. . . . . . . . . . . . . . . . . . . . . . . . .  |  Zweite Page
13
. . . . . . . . . . . . . . . . . . . . . . . . .  |
14
. . . . . . . . . . . . . . . . . . . . . . . . .  |
15
. . . . . . . . . . . . . . . . . . . . . . . . .  |
16
. . . . . . . . . . . . . . . . . . . . . . . . . /

Das in einer Zeile Text unmissverständlich zu beschreiben, ist sicher 
eine Kunst für sich.

von Stefan F. (Gast)


Lesenswert?

J. T. schrieb:
> Super, nun leuchten Pixel auf dem Display. Mit der
> Initialisierunssequenz von Stefanus ging es dann.

Blöderweise enthält das Datenblatt des SSD1306 keine klaren 
Informationen zur korrekten Initialisierung. Die findest du aber (schön 
mit Diagramm) im Datenblatt der Displays (OLED+Chip+Kabel).

von J. T. (chaoskind)


Lesenswert?

Stefanus F. schrieb:
> Blöderweise enthält das Datenblatt des SSD1306 keine klaren
> Informationen zur korrekten Initialisierung.

Ja das ist mir allerdings auch aufgefallen. Aber mit deiner Initsequenz 
hat es dann ja auch bei mir geklappt. Wobei ich aber meine, in einem 
Datenblatt vom 1306 auch mal eine Auflistung von Registern gesehen hab, 
die von der Reihenfolge her die Initsequenz gewesen sein könnte. Sollte 
sie es gewesen sein, wurde allerdings nirgendwo erwähnt, das sie es ist.

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.