Forum: Mikrocontroller und Digitale Elektronik NHD-2.7-12864WDW3 mit SSD1322 - Grayscale Problem


von Adam P. (adamap)


Angehängte Dateien:

Lesenswert?

Hallo zusammen,

für ein neues Projekt muss ich das genannte Display in Betrieb nehmen 
und bin etwas verwirrt was das Datenblatt betrifft, bezogen auf das was 
ich beobachte.

Display:
https://de.newhavendisplay.com/2-7-inch-white-graphic-oled-module/

SSD1322:
https://support.newhavendisplay.com/hc/en-us/article_attachments/4414477845911

Bevor ich die Ansteuerung per SPI & DMA realisiere, wollte ich das 
Display erstmal "kennenlernen" und habe dafür diesen Bsp.-Code für 
Arduino verwendet:
https://support.newhavendisplay.com/hc/en-us/articles/4413877789591-NHD-2-7-12864WD-with-Arduino

Nun zu meinem Verständnisproblem:
Laut SSD1322 Datenblatt werden immer 4 Bit zu einem Pixel abgebildet (16 
Graustufen).

1 Beobachtung:
Falls dies wirklich so wäre, dann müsste ich ja nur 64 Byte übertragen 
um alle 128 Pixel in einer Zeile anzusteuern. Dem ist jedoch nicht so.
Ich muss 128 Byte senden.

2 Beobachtung:
Ich habe den Eindruck, dass ich mehr als nur 16 Graustufen darstellen 
kann.
Könnte es sein, dass Newhaven 2 Segmente zu einem Pixel zusammengefasst 
hat? Was die 1 Beobachtung erklären würde.

Im angehängten Code habe ich mal 5 Fälle abgebildet um es mal zu 
vergleichen:
1. Balken mit 10px Höhe, Bit 3:0, Pixel = 0x0F
2. Balken mit 10px Höhe, Bit 7:4, Pixel = 0xF0
3. Graustufen 0-127
4. Graustufen 128-255
5. Graustufen 0-16 gleichzeitig auf Bit 7:4 & Bit 3:0

Habe mal versucht so gut wie möglich ein Foto zu machen, die Nr. 
entsprechen den genannten Fällen.

Hoffe mir kann von euch jmnd auf die Sprünge helfen, denn irgendwie 
ergibt das alles keinen Sinn für mich.

Gruß
Adam

: Bearbeitet durch User
von Harald K. (kirnbichler)


Lesenswert?

Statt irgendwelche gleichförmigen Balken auszugeben, schreib' doch 
einfach hintereinander die Werte 0, 1, 2 etc. bis 255.
In einer weiteren Zeile: Schreibe abwechselnd 0x0f und 0xf0.

Sieh Dir das Resultat an.

von Adam P. (adamap)


Lesenswert?

Harald K. schrieb:
> schreib' doch
> einfach hintereinander die Werte 0, 1, 2 etc. bis 255.
> In einer weiteren Zeile: Schreibe abwechselnd 0x0f und 0xf0.

Das habe ich ja gemacht nur mit 10px Höhe um es besser zu erkennen.

von Adam P. (adamap)


Lesenswert?

Harald K. schrieb:
> Sieh Dir das Resultat an.

Das Resultat sehe ich ja,
jedoch versteh ich nicht wie das zum Datenblatt passt, bzw. warum es 
sich so verhält.

von Harald K. (kirnbichler)


Lesenswert?

Adam P. schrieb:
> Das habe ich ja gemacht nur mit 10px Höhe um es besser zu erkennen.

Wie hast Du das gemacht?

Mit dem Arduino-Beispielcode? Wenn ja, genau wie? Zeig den Code. Exakt 
den, den Du nutzt.
Wenn nein: Wie sonst?

von Adam P. (adamap)


Lesenswert?

Harald K. schrieb:
> Mit dem Arduino-Beispielcode? Wenn ja, genau wie? Zeig den Code. Exakt
> den, den Du nutzt.
> Wenn nein: Wie sonst?

Ist im Anhang zu finden, siehe in der loop().

von Harald K. (kirnbichler)


Lesenswert?

Gut. Und, wie sieht das Ding aus, wenn Du nichts anderes machst als 
"data(0xf0); data(0x0f);" 32 mal hintereinander aufzurufen?

von Adam P. (adamap)


Lesenswert?

Harald K. schrieb:
> Gut. Und, wie sieht das Ding aus, wenn Du nichts anderes machst als
> "data(0xf0); data(0x0f);" 32 mal hintereinander aufzurufen?

Genau so wie Balken 1 & 2. Kein Unterschied.
Aber das sieht man doch schon auf dem Bild.

Ob ich nun jedes Byte immer umswitche oder mit 0x0F 10x128px zeichne und 
dann nochmal 10x128px mit 0xF0, macht doch kein Unterschied.

Mir fehlt der Zusammenhang zwischen Byte und dem GDDRAM.
Denn anscheinend ist z.B. 0xF0 nicht für 1px den dann wäre es ja hell 
weiß,
dafür muss ich das Byte jedoch auf 0xFF setzen.

edit:
Weiterhin ist mir grad aufgefallen. Einzelnes Pixel kann ich gar nicht 
übertragen, es müssen immer 2 Byte sein, sonst übernimmt der SSD1322 die 
Daten nicht.

: Bearbeitet durch User
von Harald K. (kirnbichler)


Lesenswert?

Adam P. schrieb:
> Genau so wie Balken 1 & 2. Kein Unterschied.

Aha.

Dann probier halt 0x0f 0x00 0xf0 0x00

Und beschreibe nur genau eine Zeile.

von Adam P. (adamap)


Lesenswert?

Harald K. schrieb:
> Aha.
>
> Dann probier halt 0x0f 0x00 0xf0 0x00
>
> Und beschreibe nur genau eine Zeile.

Irgendwie habe ich den Eindruck, du verstehst mein problem nicht so 
recht.

von Harald K. (kirnbichler)


Lesenswert?

Adam P. schrieb:
> Irgendwie habe ich den Eindruck, du verstehst mein problem nicht so
> recht.

Irgendwie habe ich hingegen den Eindruck, daß Du Dein Problem nicht 
durch systematisches Vorgehen lösen willst.

von Adam P. (adamap)


Lesenswert?

Harald K. schrieb:
> Irgendwie habe ich hingegen den Eindruck, daß Du Dein Problem nicht
> durch systematisches Vorgehen lösen willst.

Ja, ich als Entwickler bin chaotisch und beherrsche die systematische 
Analyse nicht.

Hast du dir den Code überhaupt mal angeschaut?
Da habe ich 5 Arten ausprobiert um das Verhalten zu analysieren.

Du hast mir nur das vorgeschlagen, was ich bereits gemacht habe.

von Harald K. (kirnbichler)


Lesenswert?

Adam P. schrieb:
> Du hast mir nur das vorgeschlagen, was ich bereits gemacht habe.

Nein, genau das hast Du nicht gemacht.

a) Du hast 128 mal den Wert 0x0F ausgegeben (und das zehn Mal 
nacheinander)

b) Du hast 128 mal den Wert 0xF0 ausgegeben (und das zehn Mal 
nacheinander)

c) Du hast die Werte 0..127 augegeben (und das zehn Mal nacheinander)

d) Du hast die Werte 128..255 augegeben (und das zehn Mal nacheinander)

e) Du hast die 16 Werte 0, 0x11, 0x22 etc. bis 0xFF jeweils 128 Mal 
ausgegeben.


Was Du nicht gemacht hast, ist das alternierende Ausgeben von 0x0F und 
0xF0, und auch nicht 0x0F, 0x00, 0xf0, 0x00

von Adam P. (adamap)


Lesenswert?

Harald K. schrieb:
> Was Du nicht gemacht hast, ist das alternierende Ausgeben von 0x0F und
> 0xF0, und auch nicht 0x0F, 0x00, 0xf0, 0x00

Doch, siehe:

Adam P. schrieb:
> Harald K. schrieb:
>> Gut. Und, wie sieht das Ding aus, wenn Du nichts anderes machst als
>> "data(0xf0); data(0x0f);" 32 mal hintereinander aufzurufen?
>
> Genau so wie Balken 1 & 2. Kein Unterschied.
1
for(uint8_t j=0; j<128; j++)
2
{
3
    if (j%2)
4
        ssd1322_data(0x0F);
5
    else
6
        ssd1322_data(0xF0);
7
}
Das Ergebnis ist einfach ein grauer Streifen.

Edit:
Mal abgesehen von der Grauabstufung, finde ich es halt seltsam das laut 
DB 4 Pixel mit 2 Byte angesprochen werden sollten. Übertrage ich jedoch 
2 Byte [0xFF, 0xFF] dann leuchten lediglich 2 Pixel.

: Bearbeitet durch User
von Harald K. (kirnbichler)


Lesenswert?

Dann probier' mal das hier:
1
for(uint8_t j=0; j<32; j++)
2
{
3
    ssd1322_data(0x0F);
4
    ssd1322_data(0x00);
5
    ssd1322_data(0xF0);
6
    ssd1322_data(0x00);
7
}

und das hier:
1
for(uint8_t j=0; j<16; j++)
2
{
3
    ssd1322_data(0x0F);
4
    ssd1322_data(0x00);
5
    ssd1322_data(0x00);
6
    ssd1322_data(0x00);
7
    ssd1322_data(0xF0);
8
    ssd1322_data(0x00);
9
    ssd1322_data(0x00);
10
    ssd1322_data(0x00);
11
}

von Adam P. (adamap)


Lesenswert?

Gleich hell nur anderes Muster.

1
|X-X-X-X-X-X-X-X-X|
2
|X---X---X---X---X|

Aber ich weiß auch net so recht was du da versuchst.
Es geht mir nicht um die Reihenfolge der Bytes, sondern um die Zuordnung 
innerhalb eines Pixels.

Ist ja wohl klar, das da immer on/off kommt, wenn ich abwechselnd 0 oder 
F sende.
Ich möchte jedoch gern die Grauabstufung verstehen, da diese anscheinend 
nicht zum SSD1322 DB passt.

: Bearbeitet durch User
von Harald K. (kirnbichler)


Lesenswert?

Adam P. schrieb:
> Aber ich weiß auch net so recht was du da versuchst.

Na, offenkundig gibt es schon einen Konflikt zwischen "ein Byte 
schreiben" und "zwei Pixel erwarten".

Wieviele Pixel werden aktiviert, wenn Du nach dem Löschen des Displays 
genau ein Byte mit dem Wert 0xFF schreibst?

von Adam P. (adamap)


Lesenswert?

Harald K. schrieb:
> Na, offenkundig gibt es schon einen Konflikt zwischen "ein Byte
> schreiben" und "zwei Pixel erwarten".

Ah ne, sag bloß.
Das versuche ich seit dem ersten Post zu sagen.

von Harald K. (kirnbichler)


Lesenswert?

Adam P. schrieb:
> Das versuche ich seit dem ersten Post zu sagen.

Und deswegen sollst Du bessere Diagnose anstellen.

Also: Was passiert, wenn Du nur genau ein Byte mit dem Wert 0xFF 
schreibst?

Was passiert, wenn Du ein Byte mit dem Wert 0x0F und dann nach einer 
spürbaren Wartezeit ein zweites Byte mit dem Wert 0x0F schreibst?

Und was geschieht, wenn Du die Prozedur mit 0xF0 wiederholst?

Nimm eine Deiner Schleifen und baue eine massive Verzögerung ein, so daß 
nur ein Byte pro Sekunde geschrieben wird. Wie ändert sich der 
Displayinhalt?

Beitrag #7550331 wurde vom Autor gelöscht.
von Adam P. (adamap)


Angehängte Dateien:

Lesenswert?

Nach weiteren Tests bin ich nun zu folgenden Erkenntnissen gekommen, für 
alle die es interessiert und evtl. mal auf das gleiche Probleme stoßen.

Bezogen auf das Newhaven Display, die haben anscheinend ihre eigene
Suppe mit dem SSD1322 gekocht.

- 1 px entspricht 1 Byte
- Es müssen mindestens 2 Byte übertragen werden, bevor diese übernommen 
werden.
- Die einzelne Inkrementierung des unteren sowie oberen Nibbles 
resultiert in gleichen Graustufen (nicht volle Helligkeit).

Test 1:
0x00, 0x01, 0x02 ... 0x0F

Test 2:
0x00, 0x10, 0x20 ... 0xF0

- Die Reihenfolge:

0x00, 0x01, 0x02 ... 0x0F, 0x1F, 0x2F ... 0xFF

(erst unteres Nibble bis max., dann das obere Nibble inkrementieren) hat 
beim Übergang von 0x0F zu 0x1F einen zu großen Helligkeitssprung.

- Durch das gleichzeitige Inkremetieren des unteren sowie oberen Nibbles 
erhält man eine schöne Grauabstufung. Wobei der Wert 0x11 wie schwarz 
aussieht, mit der default grayscale table des SSD1322.
(siehe Bild)

Testbild wurde wie folgt generiert (unterer weiße Bereich dient zur 
Kontrolle der max. Helligkeit)
1
  /* 32 px Höhe */
2
  for(uint16_t i=0; i<32; i++)
3
  {
4
    /* 16 Graustufen */
5
    for (uint16_t j=0; j<16; j++)
6
    {
7
      px = (j << 4) | j;
8
      
9
      /* 8 px Breite */
10
      for (uint16_t k=0; k<8; k++)
11
      {
12
        ssd1322_data(px);
13
      }
14
    }
15
  }
16
  
17
  /* 1px Linie schwarz */
18
  for (uint16_t i=0; i<128; i++)
19
    ssd1322_data(0x00);
20
  
21
  /* 31 x 128 px weiß */
22
  for (uint8_t i=0; i<31; i++)
23
  {
24
    for(uint8_t j=0; j<128; j++)
25
    {
26
      ssd1322_data(0xFF);
27
    }
28
  }

Somit ist das Problem für mich erstmal gelöst, wäre einfacher gewesen 
hätte sich Newhaven daran gehalten wie es eigentlich mit dem SSD1322 
sein sollte.

P.S.
Das die column Koordinate = 0x1C, X=0 enspricht liegt daran, dass 
Newhaven aufgrund des Layouts einfach die vorderen Segmente nicht 
verwendet:

https://support.newhavendisplay.com/hc/en-us/community/posts/11282300100503--Solved-Column-Start-Address-0x1C-Column-Addressing-on-NHD-3-12-25664-

Gruß Adam

: Bearbeitet durch User
von Harald K. (kirnbichler)


Lesenswert?

Ist der auf Deinem Bild zu sehende graue Rand rechts und um den unteren 
weißen Balken herum ein Artefakt Deiner Photographie?

von Adam P. (adamap)


Angehängte Dateien:

Lesenswert?

Harald K. schrieb:
> Ist der auf Deinem Bild zu sehende graue Rand rechts und um den unteren
> weißen Balken herum ein Artefakt Deiner Photographie?

Der "graue Rand" der aussieht wie Anti aliasing ist bedingt durch die 
Kamera.

Das einzige was ist, die erste Zeile vom weißen Rechteck (rote Pfeile 
auf Bild) ist etwas dunkler als 0xFF.
Dies liegt aber eher an den SEG / COM Treibern.

Spielt für unsere Anwendungsfall keine große Rolle, da ich eher selten 
soviel weiße Fläche darstellen werde, dass da die Last so hoch wird.

: Bearbeitet durch User
von Harald K. (kirnbichler)


Lesenswert?

Na dann .. gratuliere: Du hast eine Erklärung für das vom Datenblatt 
abweichende Verhalten gefunden und offenkundig auch eine für Dich 
verwendbare Lösung.

Gut zu wissen, daß derartige Displays auch "anders" sein können.

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.