Forum: Mikrocontroller und Digitale Elektronik Einschaltung und Löschung OLED Display


von Sascha T. (ernie1973)


Lesenswert?

Hallo Zusammen,

aktuell habe ich ein Bolymin OLED Grafikdisplay 128x64 (SSD1303) über 
SPI Schnittstelle in Betrieb genommen. Mittlerweile klappt auch alles so 
weit ganz gut.

Aktuell habe ich nur noch zwei Problemchen:

1. Es  wird nach dem Einschalten noch kurz das letzte Bild angezeigt, 
bevor die Initialisierung startet. Kann ich das noch irgendwie 
softwaremäßig verbessern oder müsste ich hier hardwaremäßig die 
Versorgungsspannung erst später zuschalten?

2. Die Löschung des gesamten Display dauert relativ lange, da ich hier 
jeden Pixel einzeln lösche. Gibt es irgendwie die Möglichkeit dies über 
Initialisierungsbefehle schneller zu erledigen?

Vielen Dank schonmal im voraus. Anbei noch meine aktuelle 
Initialisierungsroutine.

Besten Dank,

Sascha
1
Init_LCD:
2
   
3
  wdr
4
5
  ldi   Merker,$AE                       ; Set Display (AF=ON , AE=OFF)
6
  call   Write_Instr  
7
8
  call  Display_Reset
9
10
  ldi   Merker,$40
11
  call  Write_Instr  
12
  ldi   Merker,$A0                       
13
  call  Write_Instr  
14
  ldi   Merker,$DA                      ; Set Pins Hardware
15
  call  Write_Instr                      
16
  ldi   Merker,$12   
17
  call  Write_Instr
18
19
  ldi   Merker,$C8                    
20
  call  Write_Instr  
21
22
  ldi   Merker,$A8                       ; Set Multiplex Ratio
23
  call  Write_Instr                       
24
  ldi   Merker,$3F
25
  call  Write_Instr
26
27
  ldi   Merker,$D5                       ; Set Clock Divide
28
  call  Write_Instr                         
29
  ldi   Merker,$40
30
  call  Write_Instr 
31
32
  ldi   Merker,$DB                       ; VCOM Deselect Level
33
  call  Write_Instr                         
34
  ldi   Merker,$40
35
  call  Write_Instr 
36
37
  ldi   Merker,$D9                       ; Discharge period
38
  call  Write_Instr                       
39
  ldi   Merker,$1F                       ; 
40
  call  Write_Instr 
41
42
  ldi   Merker,$D3                       ; Set Display Offset
43
  call  Write_Instr                   
44
  ldi   Merker,$00                      
45
  call  Write_Instr 
46
47
  ldi   Merker,$40                      ; Set Display Start Line
48
  call  Write_Instr  
49
50
  ldi   Merker,$A4                       ; A4=ON
51
  call  Write_Instr                     
52
53
  ldi   Merker,$A6                       ; Normal Display
54
  call  Write_Instr  
55
56
  ldi   Merker,$81                       ; Set Contrast Control
57
  call  Write_Instr
58
  ldi   Merker,$FF                      ; 0-255
59
  call  Write_Instr    
60
61
  ldi   Merker,$AD                       ; Set DC-DC
62
  call  Write_Instr                       
63
  ldi   Merker,$8A                       ; 8B=ON, 8A=Off
64
  call  Write_Instr   
65
66
  call  Pause_10ms
67
68
  ldi   Merker,$AF                       ; Set Display (AF=ON , AE=OFF)
69
  call  Write_Instr                                    
70
  call  pause_10ms
71
  ret
72
73
; -------------------------------------------------------------------------
74
75
Display_Reset:   
76
  wdr 
77
  sbi   PortC,6                        ; D/C (H:Data; L: Command) 
78
  sbi   PortC,5                        ; CS  
79
  call  Pause_1ms    
80
  sbi   PortC,4
81
  call  Pause_10clk
82
  cbi   PortC,4
83
  call  Pause_1ms
84
  sbi   PortC,4
85
  call  Pause_200ms
86
  ret

von Falk B. (falk)


Lesenswert?

@ Sascha T. (ernie1973)

>1. Es  wird nach dem Einschalten noch kurz das letzte Bild angezeigt,
>bevor die Initialisierung startet. Kann ich das noch irgendwie
>softwaremäßig verbessern

Möglicherweise muss man so zeitig wie möglich bei der Initialisierung 
das Display per Befehl abschalten.

Set Display ON/OFF

> 2. Die Löschung des gesamten Display dauert relativ lange,

Wie lange?

>da ich hier
>jeden Pixel einzeln lösche.

Wie genau? Eingentlich muss man nur einmal die Adresse 0 setzen und dann 
132 x 64 Bit = 8448 Bit = 1056 Bytes schreiben. Der Adresszähler wird 
automatisch hochgezählt. Das LCD verträgt maximal 4 MHz SPI-Takt, macht 
für 1056 Bytes 2,1 ms. Sprich, man kann es pro Sekunde ca. 473 mal 
löschen. Reicht das nicht?

Poste vollständigen Code als Anhang, dann kann man dir helfen.

von Sascha T. (ernie1973)


Lesenswert?

Vielen Dank für die Hinweise.

Ich habe jetzt mal in der Routine laut Anhang alle Pixel nacheinander 
beschrieben und es geht sehr schnell, sa dass man die Verzögerung nicht 
mehr merkt. Zuvor habe ich es über meinen Zeichenroutine mit einem 
leeren Zeichen gemacht, das hat dann deutlich länger gebraucht und man 
hat den Löschvorgang halt "gesehen", wenn das Display während dessen 
aktiviert war.

Bei der u.a. Routine habe ich nur das merwürdig Verhalten, dass ich eine 
Spalte mehr löschen muss. Annsonsten wird beim zweiten Durchlauf die 
letzte Spalte nicht gelöscht, aber dann komischerweise beim dritten. Am 
Ende bleibt aber die allerletzte Spalte ungelöscht! Mit den 129 
Durchläufen funkioniert es aber!

Bezüglich des Einschalten schalte ich das Display ja in der Init sofort 
aus, welche kurz nach den Portdefinitionen im Hauptprogramm durchgeführt 
wird. Man kann aber das alte Bild nur sehen, wenn das Gerät nach dem 
Abschalten relativ schnell wieder eingeschaltet wird. Wartet man 10s 
nach dem Ausschalten sieht man auch kein Bild mehr!

1
LCD_Clear:
2
  wdr  
3
4
  ldi   Merker,$AE                      ; Set Display (AF=ON , AE=OFF)
5
  call  Write_Instr  
6
7
  ldi   temp,$02                        ; Setze auf erste Spalte
8
  sts   sSpalteLow,temp
9
  ldi   temp,$10
10
  sts   sSpalteHigh,temp
11
12
  ldi   temp,$B0                        ; Lösche erste Zeile
13
  sts   sZeile,temp
14
  call  LCD_Clear_Zeile
15
16
  ldi   temp,$B1
17
  sts   sZeile,temp
18
  call  LCD_Clear_Zeile
19
20
  ldi   temp,$B2
21
  sts   sZeile,temp
22
  call  LCD_Clear_Zeile
23
24
  ldi   temp,$B3
25
  sts   sZeile,temp
26
  call  LCD_Clear_Zeile
27
28
  ldi   temp,$B4
29
  sts   sZeile,temp
30
  call  LCD_Clear_Zeile
31
  
32
  ldi   temp,$B5
33
  sts   sZeile,temp
34
  call  LCD_Clear_Zeile
35
36
  ldi   temp,$B6
37
  sts   sZeile,temp
38
  call  LCD_Clear_Zeile
39
  
40
  ldi   temp,$B7
41
  sts   sZeile,temp
42
  call  LCD_Clear_Zeile     
43
  
44
  ldi   Merker,$AF                       ; Set Display (AF=ON , AE=OFF)
45
  call  Write_Instr  
46
  ret
47
48
; Löscht eine Zeile
49
LCD_Clear_Zeile:                        ; Die Routine muss aktuell einmal mehr durchlaufen werden, da ansonsten beim zweiten
50
  wdr                                   ; Aufruf die letzte Spalte nicht direkt beschrieben wird, sondern erst beim nächsten Durchlauf   
51
52
  lds   Merker,sSpalteLow
53
  call  Write_Instr
54
  lds   Merker,sSpalteHigh
55
  call  Write_Instr
56
  lds   Merker,sZeile
57
  call  Write_Instr
58
59
  ldi   temp,129
60
  sts   sMerker,temp
61
62
LCD_Clear_Zeile_Schleife:                      
63
  wdr                      
64
  ldi   Merker,$00
65
  call  write_data
66
  lds   temp,sMerker
67
  dec   temp
68
  sts   sMerker,temp
69
  cpi   temp,0
70
  brne  LCD_Clear_Zeile_Schleife
71
  ret

von Frank M. (frank_m35)


Lesenswert?

Also idealerweise schaltet man OLED Displays so an und aus:
http://www.farnell.com/datasheets/303159.pdf
Seite 17

Das geht bei dir aber nicht, da der Spannungswandler fuer das Panel mit 
an Board ist.

Du koenntest beim Abschalten den Inhalt loeschen.

von Falk B. (falk)


Lesenswert?

@Sascha T. (ernie1973)

>Ich habe jetzt mal in der Routine laut Anhang alle Pixel nacheinander

Keine Anhang, du hast den Querllcode in den Text kopiert. Naja, geht bei 
der Länge gerade noch so.

>beschrieben und es geht sehr schnell, sa dass man die Verzögerung nicht
>mehr merkt.

Ist aber noch viel Luft drin.

> Zuvor habe ich es über meinen Zeichenroutine mit einem
>leeren Zeichen gemacht, das hat dann deutlich länger gebraucht

Logisch.

>Bei der u.a. Routine habe ich nur das merwürdig Verhalten, dass ich eine
>Spalte mehr löschen muss. Annsonsten wird beim zweiten Durchlauf die
>letzte Spalte nicht gelöscht, aber dann komischerweise beim dritten. Am
>Ende bleibt aber die allerletzte Spalte ungelöscht! Mit den 129
>Durchläufen funkioniert es aber!

Hmm, ich verstehe sowieso nicht ganz die Speicherorganisation. Wie 
spricht man die 1k SPeicher an? Über Page und Coloum, klar, aber was 
gehört wie zusammen?

Egal. Deine Routine kann man noch um einiges verbessern.

1. Nutze eine Schelife, um die 8 Pages einzustellen und zu löschen.
2. Eine Schleife, die sehr oft möglichst schnell durchlaufen werden 
soll, nutzt am Besten Register fpr Variablen und keinen SRAM. Ausserdem 
Kopiert man den Quelltext für den SPI-Zugriff hier direkt rein und macht 
keinen call, denn das dauert auch einige Takte. Und schmeiß diesen WDR 
raus, der nervt.
1
  ldi   r16,129   // Zähler
2
  ldi   r17,0   // Leer-Daten
3
LCD_Clear_Zeile_Schleife:                      
4
  sbis  spcr, spif
5
  rjmp  LCD_Clear_Zeile_Schleife
6
  out   spdr, r17
7
  dec   r16
8
  brne  LCD_Clear_Zeile_Schleife
9
  ret

MFG
Falk

von Falk B. (falk)


Lesenswert?

Wegen der 129 statt 128 Zugriffe.

Seite 17.

"During data writing, an additional NOP command should be inserted 
before the CS# goes high (Refer to Figure 6."

Wobei hier wohl das Commando 0xE3 gemeint ist, es gibt mehrere NOPs.

von Falk B. (falk)


Lesenswert?

1
  ldi   r16,129   // Zähler
2
  ldi   r17,0   // Leer-Daten
3
  sbi   portx, pdx  // D/C bit setzen
4
LCD_Clear_Zeile_Schleife:                      
5
  sbis  spsr, spif
6
  rjmp  LCD_Clear_Zeile_Schleife
7
  out   spdr, r17
8
  dec   r16
9
  brne  LCD_Clear_Zeile_Schleife
10
11
  ldi   r17,$E3   // NOP
12
  cbi   portx, pdx  // D/C bit loeschen
13
LCD_Clear_2:
14
  sbis  spsr, spif
15
  rjmp  LCD_Clear_2
16
  out   spdr, r17
17
18
  ret

von Sascha T. (ernie1973)


Lesenswert?

Frank M. schrieb:
> Also idealerweise schaltet man OLED Displays so an und aus:
> http://www.farnell.com/datasheets/303159.pdf
> Seite 17
>
> Das geht bei dir aber nicht, da der Spannungswandler fuer das Panel mit
> an Board ist.

Ja, das wäre wohl besser. Ich habe halt gedacht, ob ich es irgendwie 
durch den Hardware Reset oder einen Software Befehl wie z.B. den "Set 
DC-DC" hinbekomme. Das klappt aber nicht.

> Du koenntest beim Abschalten den Inhalt loeschen.

Das wäre die sauberste Lösung, aber es geht bei dem Gerät leider nicht, 
da der Nutzer die Spannungsversorgung über eine Netzschalter trennen 
kann.

Aber vielen Dank für die Hilfestellung!

Gruß,

Sascha

von Sascha T. (ernie1973)


Lesenswert?

Falk Brunner schrieb:
> Wegen der 129 statt 128 Zugriffe.
>
> Seite 17.
>
> "During data writing, an additional NOP command should be inserted
> before the CS# goes high (Refer to Figure 6."
>
> Wobei hier wohl das Commando 0xE3 gemeint ist, es gibt mehrere NOPs.

Vielen Dank für die Hinweise bezüglich der Löschroutine, das werde ich 
mal umsetzen.

Die o.a. Beschreibung halte ich eigentlich in meinen Schreibroutinen 
ein:
1
Write_Instr:
2
  wdr
3
  
4
  cbi   PortC,6          ; D/C (H:Data; L: Command) 
5
  cbi   PortC,5          ; CS
6
  nop
7
  nop
8
  call   SPI_Senden
9
  nop
10
  nop
11
  sbi   PortC,6          ; D/C (H:Data; L: Command) 
12
  sbi   PortC,5          ; CS
13
  ret
14
15
Write_Data:
16
  wdr
17
18
19
  sbi   PortC,6          ; D/C (H:Data; L: Command) 
20
  cbi   PortC,5          ; CS
21
  nop
22
  nop
23
  call   SPI_Senden
24
  nop
25
  nop
26
  sbi   PortC,6          ; D/C (H:Data; L: Command) 
27
  sbi   PortC,5          ; CS
28
  ret

von Falk B. (falk)


Lesenswert?

@ Sascha T. (ernie1973)

>Die o.a. Beschreibung halte ich eigentlich in meinen Schreibroutinen
>ein:

Defensiv und strukturiert programmierein ist ja gut, aber man kann es 
auch übertreiben. Schau dir mal an, wieviel Funtkionsaufrufe bei dir 
gemacht werden, ehe ein Byte über SPI raus geht! Und es reicht, VOR der 
Operation D/C zu setzen, danach kann es stehen bleiben wie es ist.

von Sascha T. (ernie1973)


Lesenswert?

Falk Brunner schrieb:
> @ Sascha T. (ernie1973)
>
>>Die o.a. Beschreibung halte ich eigentlich in meinen Schreibroutinen
>>ein:
>
> Defensiv und strukturiert programmierein ist ja gut, aber man kann es
> auch übertreiben. Schau dir mal an, wieviel Funtkionsaufrufe bei dir
> gemacht werden, ehe ein Byte über SPI raus geht! Und es reicht, VOR der
> Operation D/C zu setzen, danach kann es stehen bleiben wie es ist.

Da magst Du Recht haben, aber die Struktur ist uns in der Entwicklung 
schon sehr wichtig und es hat ja im Grunde "nur" 
Geschwindigkeitseinbußen, die jetzt auch bei der neuen Löschroutine 
nicht mehr merkbar sind.

Teilweise sind es auch noch Überbleibsel aus der Inbetriebnahme des 
Displays, die aus diversen Gründen nicht so einfach war, so dass wir 
lieber noch etwas mehr gewartet haben oder den Port nochmal definiert 
haben, wie in dem geschilderten Fall.

Für das SPI benutzen wir aktuell auch noch eine Softwareschnittstelle, 
da die Hardware mal wieder anders belegt war.

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.