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
|
@ 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.
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
|
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.
@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
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.
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
|
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
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
|
@ 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.
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.
|