Hallo,
nachdem mir hier mal vor einem Jahr so kompetent in Sachen LCD12232
geholfen wurde, wollte ich mich nun an ein komplexeres Gerät wagen, das
TG12864B von Pollin. Dazu gibt es schon einige Beiträge hier, auch eine
C-Bibliothek... aber ich schreibe aus Lerngründen gern in Assembler.
Das aktuelle Problem ist: Ich kriege das Display am ATMega8A auf dem
myAVR-Board zum Laufen (mit getrennten Pins für die Datenleitungen an
Port B/C 0..3 und Steuerpins D/I, CS1/2, R/W, E, Reset an Port D 2-7),
aber nicht am ATMega8535. Hier habe ich das Display mit den
Datenleitungen DB0..7 an Port A und mit den Steuerleitungen an Port C
liegen. Der Kontrast lässt sich einstellen, es zeigt aber nichts an. Ich
assoziiere das aktuell mit "Display off", irgendein Müll schwirrt
eigentlich immer im RAM rum.
Offensichtliche Unterschiede sind
a) die Controller (Pins alle überprüft, schalten fröhlich zwischen high
und low hin und her)
b) die Takte, der m8A auf dem myAVR-Board lief mit Eigentakt (~1MHz),
der m8535 mit einem Quarz mit 7.3728MHz -- dafür hab ich in transmit_12
Takte je Display-Befehl eingebaut
c) die Trennung der Datenpins auf dem myAVR-Board (sollte eigentlich
keinen Einfluß haben)
Da in diesem Forum fast ebensoviele Ansteuer-Beispiele wie Beiträge
existieren, hab ich mal alles mögliche durchprobiert. Der folgende Code
tut auf dem myAVR-Board mit m8A (die wait-Routinen warten die korrekte
Zeit, das ist ausprobiert). Hier fehlt ein Schreib-Befehl für RAM-Daten,
aber das Prinzip ist gleich und funktioniert:
1
.include "m8Adef.inc"
2
3
.equ TG12864_CS1=3
4
.equ TG12864_CS2=2
5
.equ TG12864_RST=4
6
.equ TG12864_E=5
7
.equ TG12864_RW=6
8
.equ TG12864_DI=7
9
10
ldi r16, low(RAMEND)
11
out SPL, r16
12
ldi r16, high(RAMEND)
13
out SPH, r16
14
15
; PortB, C, D are used as output (bei myAVR jew. nur sechs Pins verfügbar)
16
sbi DDRB, 0
17
sbi DDRB, 1
18
sbi DDRB, 2
19
sbi DDRB, 3
20
21
sbi DDRC, 0
22
sbi DDRC, 1
23
sbi DDRC, 2
24
sbi DDRC, 3
25
26
sbi DDRD, 2
27
sbi DDRD, 3
28
sbi DDRD, 4
29
sbi DDRD, 5
30
sbi DDRD, 6
31
sbi DDRD, 7
32
33
; Initialisierung
34
cbi PORTB, 0
35
cbi PORTB, 1
36
cbi PORTB, 2
37
cbi PORTB, 3
38
39
cbi PORTC, 0
40
cbi PORTC, 1
41
cbi PORTC, 2
42
cbi PORTC, 3
43
44
sbi PORTD, TG12864_CS2
45
sbi PORTD, TG12864_CS1
46
sbi PORTD, TG12864_RST
47
sbi PORTD, TG12864_E
48
cbi PORTD, TG12864_RW
49
cbi PORTD, TG12864_DI
50
51
; command pins are on PortD (defined above), data pins are on PortB (lower half byte) and PortC (higher half byte) due to only six pins per port on Mega8A
52
53
; reset TG12864 LCD
54
rcall wait50ms
55
cbi PORTD, TG12864_RST
56
rcall wait50ms
57
sbi PORTD, TG12864_RST
58
rcall wait50ms
59
60
; start TG12864 LCD
61
; 0b1111 für PortB
62
; 0b0011 für PortC
63
sbi PORTB, 0
64
sbi PORTB, 1
65
sbi PORTB, 2
66
sbi PORTB, 3
67
sbi PORTC, 0
68
sbi PORTC, 1
69
cbi PORTC, 2
70
cbi PORTC, 3
71
cbi PORTD, TG12864_RW
72
cbi PORTD, TG12864_DI
73
74
rcall transmit_12
75
76
; set LCD start line to 0
77
; 0b[0000] für PORTB
78
; 0b11[00] für PORTC
79
cbi PORTB, 0
80
cbi PORTB, 1
81
cbi PORTB, 2
82
cbi PORTB, 3
83
cbi PORTC, 0
84
cbi PORTC, 1
85
sbi PORTC, 2
86
sbi PORTC, 3
87
cbi PORTD, TG12864_RW
88
cbi PORTD, TG12864_DI
89
90
rcall transmit_12
91
92
; set LCD page (X address) to 2
93
; 0b1[010] für PORTB
94
; 0b1011 für PORTC
95
cbi PORTB, 0
96
sbi PORTB, 1
97
cbi PORTB, 2
98
sbi PORTB, 3
99
sbi PORTC, 0
100
sbi PORTC, 1
101
cbi PORTC, 2
102
sbi PORTC, 3
103
cbi PORTD, TG12864_RW
104
cbi PORTD, TG12864_DI
105
106
rcall transmit_12
107
108
; set LCD Y address to 3
109
; 0b[0011] für PORTB
110
; 0b01[00] für PORTC
111
sbi PORTB, 0
112
sbi PORTB, 1
113
cbi PORTB, 2
114
cbi PORTB, 3
115
cbi PORTC, 0
116
cbi PORTC, 1
117
sbi PORTC, 2
118
cbi PORTC, 3
119
cbi PORTD, TG12864_RW
120
cbi PORTD, TG12864_DI
121
122
rcall transmit_12
123
;===========================
124
transmit_12:
125
push r16
126
ldi r16, 4
127
cbi PORTD, TG12864_CS1
128
cbi PORTD, TG12864_CS2
129
; loop_tm12:
130
; nop
131
; dec r16
132
; brne loop_tm12
133
sbi PORTD, TG12864_CS1
134
sbi PORTD, TG12864_CS2
135
pop r16
136
ret
Will ich denselben Code auf dem m8535 laufen lassen, angepaßt an dessen
Pin-Möglichkeiten (siehe oben), zeigt das Display einfach gar nichts an.
Auch ein exaktes Codieren des Timings im Datenblatt wie folgt zeigt
keinen Erfolg (tmp1 ist r16, tmp2 r17, Port A 6+7 sind an zwei LEDs, die
die AVR-Aktivität anzeigen sollen und das auch wie geplant tun):
1
; Stackpointer initialisieren
2
ldi tmp1, HIGH(RAMEND)
3
out SPH, tmp1
4
ldi tmp1, LOW(RAMEND)
5
out SPL, tmp1
6
7
ldi tmp1, 0xFF ; LCD ist active-low, also Start/Reset auf all-high
8
out PORTA, tmp1
9
10
; PortA-Belegungen
11
.equ DI = 0
12
.equ CS2 = 1
13
.equ CS1 = 2
14
.equ RW = 3
15
.equ E = 4
16
.equ RST = 5
17
18
cbi PORTA, RW ; R/W=0: write-Zugriff auf LCD
19
cbi PORTA, DI ; D/I=0: Instruction
20
out PORTC, tmp1
21
22
; PORTA/PORTC sind Ausgänge für LCD
23
ldi tmp1, 0xFF
24
out DDRA, tmp1
25
out DDRC, tmp1
26
27
; fürs Signal-LED-Blinken, anfangs AUS
28
cbi PORTA, 6
29
cbi PORTA, 7
30
31
rcall wait500ms
32
33
;rcall reset_LCD
34
.equ DISPLAY_ON = 0b00111111
35
.equ DISPLAY_OFF = 0b00111110
36
.equ START_LINE = 0b11000000
37
.equ SET_PAGE = 0b10111000
38
.equ SET_COLUMN = 0b01000000
39
40
; Anzeigen: Erste Sequenz
41
sbi PORTA, 6
42
rcall wait100ms
43
cbi PORTA, 6
44
45
cbi PORTA, RST
46
rcall wait100ms
47
sbi PORTA, RST
48
49
; initialisieren
50
ldi tmp1, (1<<E|1<<CS1|1<<CS2|0<<RW|0<<DI)
51
out PORTA, tmp1
52
53
; E auf low ziehen
54
cbr tmp1, E
55
out PORTA, tmp1
56
; Timing im Datenblatt: mind. 250ns (ca.)
57
rcall wait50mus
58
; CS1, CS2, DI, RW setzen
59
ldi tmp1, (0<<E|0<<CS1|0<<CS2|0<<RW|0<<DI)
60
out PORTA, tmp1
61
; Timing
62
rcall wait50mus
63
; E wieder auf high setzen
64
sbr tmp1, E
65
out PORTA, tmp1
66
; warten
67
rcall wait50mus
68
; Daten vorbereiten, damit sie bei der nächsten fallenden E-Flanke übernommen werden können
69
ldi tmp2, DISPLAY_ON
70
out PORTC, tmp2
71
; Daten senden
72
cbr tmp1, E
73
out PORTA, tmp1
74
; warten
75
rcall wait50mus
76
; alles wieder auf Ausgangswerte setzen
77
ldi tmp1, (0<<E|1<<CS1|1<<CS2|0<<RW|0<<DI)
78
out PORTA, tmp1
79
; E wieder auf high setzen: Wartestellung
80
sbr tmp1, E
81
out PORTA, tmp1
82
83
rcall wait10ms
84
85
; was schreiben als Test
86
; E auf low ziehen
87
cbr tmp1, E
88
out PORTA, tmp1
89
; Timing im Datenblatt: mind. 250ns (ca.)
90
rcall wait50mus
91
; CS1, CS2, DI, RW setzen
92
ldi tmp1, (0<<E|0<<CS1|0<<CS2|0<<RW|1<<DI) ; diesmal Daten, kein Befehl
93
out PORTA, tmp1
94
; Timing
95
rcall wait50mus
96
; E wieder auf high setzen
97
sbr tmp1, E
98
out PORTA, tmp1
99
; warten
100
rcall wait50mus
101
; Daten vorbereiten, damit sie bei der nächsten fallenden E-Flanke übernommen werden können
102
ldi tmp2, 0b11001100
103
out PORTC, tmp2
104
; Daten senden
105
cbr tmp1, E
106
out PORTA, tmp1
107
; warten
108
rcall wait50mus
109
; alles wieder auf Ausgangswerte setzen
110
ldi tmp1, (0<<E|1<<CS1|1<<CS2|0<<RW|0<<DI)
111
out PORTA, tmp1
112
; E wieder auf high setzen: Wartestellung
113
sbr tmp1, E
114
out PORTA, tmp1
Reset des Displays liegt dauerhaft auf high. Ich hatte einmal die
Display-Spannung falsch herum angelegt und daher angenommen, dass es
damit gegrillt wäre (U_min ist -0.7V für Maximum Ratings), aber auch der
Austausch erbrachte keinen Erfolg.
Hat irgendjemand eine Idee dazu? Ich bin am Ende meiner Weisheit
angelangt... nach über einer Woche Datenblattsuche, -lesen,
Rumprobieren, E von high nach low, von low nach high, gleichzeitig mit
CS1/2, versetzt, oder auch (einem Beitrag hier folgend) E ignorieren und
nur mit CS1/2 arbeiten... alles ohne Erfolg.
Danke schonmal!
Gruss,
Eingehirner
P.S.: Kann man auf einfache Art prüfen, ob das eine Display noch tut?
Die Hintergrundbeleuchtung funktioniert noch, die wird deaktiviert, wenn
die Logik falsch gepolt angeschlossen wird. Dadurch hab ichs überhaupt
erst gemerkt...
Habe in den letzten Tagen festgestellt, dass PORTA bei all meinen
Controllern nur 4.08V liefert, während PORTC und PORTD auf 4.78V liegen
(wenn vom USB-Port betrieben). Vielleicht liegts daran. Werde versuchen,
das Display auf Ports C+D zu legen und dann wieder hier berichten.
Das Problem dabei: Ich brauch die PortD-Eingänge für den externen
Interrupt... hrmpf. Naja, dann muss woh der ATMega644 her, der ist sonst
mit den 8535-Pins kompatibel und kann laut Datenblatt externe Interrupts
an ALLEN Pins.
Gruss,
Eingehirner
Des Rätsels Lösung: Die Doku von Pollin ist schlichtweg FALSCH. Das
Display wird ähnlich wie das LCD12232 angesteuert (hier für 8MHz):
Initialisierung:
RST auf high, die anderen Steuer-Pins auf low (CS1/2, E, RW, DI)
Datentransfer:
Daten auf den Datenport DB0-7 schreiben
D/I je nach Transferart auf high (Daten) oder low (Kommando) setzen und
R/W je nach Wunsch auf high (read from display) oder low (write to
display) setzen
E auf high ziehen
8-10 nops
CS1/2 (nach Belieben) auf high ziehen (high = aktiv)
8-10 nops
E auf low ziehen
8-10 nops
CS1/2 auf low ziehen
8-10 nops
Hier ein Beispielcodeschnipsel:
1
.equ DATA_PORT=PORTC
2
.equ INSTR_PORT=PORTA
3
4
; PortA Pinbelegung (Kommando-Pins):
5
.equ DI=5 ; 0: Instruction, 1: Data
6
.equ CS2=1 ; switch for left side of display
7
.equ CS1=2 ; switch for right side of display
8
.equ E=3 ; Enable
9
.equ RW=4 ; WRITE - 0: write, 1: read
10
.equ RST=0 ; Reset-Pin
11
.equ LCD_CMD = 0b100
12
.equ LCD_DATA = 0b000
13
.equ LCD_LEFT = 0b010
14
.equ LCD_RIGHT = 0b001
15
16
; PortC Pinbelegung (Daten-Pins):
17
.equ LCD_ON= 0b00111111
18
.equ LCD_OFF= 0b00111110
19
.equ LCD_STARTLINE= 0b11000000 ; use with "+ line#" (0..31)
20
.equ LCD_SETPAGE= 0b10111000 ; use with "+ page#" (0..3)
21
.equ LCD_SETCOLUMN= 0b01000000 ; use with "+ column#" (0..63)
22
23
;--------------------------
24
switch_on_LCD:
25
push r16
26
27
; Initialisierung
28
sbi DATA_PORT, RST ; Reset auf HIGH setzen
29
cbi DATA_PORT, CS1 ; inaktiv, Daten werden erst auf steigender Flanke übernommen
30
cbi DATA_PORT, CS2 ; dito
31
cbi DATA_PORT, E ; zur Aktivierung der Kommandoleitung
32
cbi DATA_PORT, DI
33
cbi DATA_PORT, RW
34
35
ldi ZH, high(lcd_params)
36
ldi ZL, low(lcd_params)
37
ldi r16, LCD_ON
38
st Z+, r16
39
ldi r16, LCD_CMD + LCD_LEFT + LCD_RIGHT ; es ist ein Kommando und geht an beide Hälften
40
st Z, r16
41
rcall SendToLCD
42
43
pop r16
44
ret
45
;-------------------------
46
SendToLCD:
47
push r16
48
push r17
49
push r18
50
ldi ZH, high(lcd_params)
51
ldi ZL, low(lcd_params)
52
ld r16, Z+ ; die Daten/Kommando-Bits
53
ld r18, Z ; das codierte Byte für links/rechts, Data/Command
54
55
; Daten/Kommando auf Datenport vorlegen
56
out DATA_PORT, r16
57
58
ldi r17, (1<<RST) ; r17 wird nachher auf INSTR_PORT ausgegeben, RST muss HIGH bleiben
59
60
; Decodierung
61
; Daten oder Kommando?
62
sbrs r18, 2
63
sbr r17, (1<<DI) ; falls es Daten sind, muss DI auf HIGH gesetzt werden; sonst ist es ja schon auf LOW
64
65
out INSTR_PORT, r17
66
sbi INSTR_PORT, E ; LCD empfangsbereit
67
68
{8x nop}
69
70
sbrc r18, 0
71
sbi INSTR_PORT, CS1
72
sbrc r18, 1
73
sbi INSTR_PORT, CS2
74
75
{8x nop}
76
sbrc r18, 0
77
cbi INSTR_PORT, CS1
78
sbrc r18, 1
79
cbi INSTR_PORT, CS2
80
81
{8x nop}
82
83
cbi INSTR_PORT, E
84
85
{8x nop}
86
87
pop r18
88
pop r17
89
pop r16
90
ret
91
;------------------------
92
.DSEG ; SRAM-Datensektion
93
lcd_params: .BYTE 2 ; erst Data, dann Maske für links/rechts und Command/Data (links/rechts/beide: 0bX10/X01/X11; Command: 0b0XX; Data: 0b1XX)
Ist eigentlich völlig primitiv, aber wenn man (vor allem hier im Forum)
immer auf die vermeintlich richtigen Datenblätter zum zugrundeliegenden
Controller verwiesen wird, dessen Verdrahtung aber auf dem Display nicht
sichtbar ist, hilft das nicht weiter. Einmal mehr zeigt sich:
mikrocontroller.net ist nur dann hilfreich, wenn man sowieso schon
Ahnung hat... Die Fragen hätten von jedem, der das TG12864 mal zum
Laufen gebracht hat, beantwortet werden können. Naja.
Eingehirner schrieb:> Des Rätsels Lösung: Die Doku von Pollin ist schlichtweg FALSCHEingehirner schrieb:> Ich kriege das Display am ATMega8A auf dem myAVR-Board zum Laufen...> aber nicht am ATMega8535.
Eine falsche Dokumentation (des Displays) erklärt nicht, wieso es an
einem µC läuft und am anderen nicht. Da war eher Meister Zufall der
Gehilfe.
> Einmal mehr zeigt sich:> mikrocontroller.net ist nur dann hilfreich, wenn man sowieso schon> Ahnung hat...
Überdenke nochmal den Aufbau deiner Postings (Netiquette). Es ist nicht
nett, mehrere Seiten lange Quelltexte direkt in den Beitrag zu setzen,
die gehören als Datei in den Anhang. Zudem ist der Code schlecht
kommentiert. Wenn ich in einen Thread reinklicke und sowas sehr, vergeht
mir sofort die Lust am Lesen, anderen wohl auch.
Hi
>Des Rätsels Lösung: Die Doku von Pollin ist schlichtweg FALSCH.
Von welchem der drei TC12864B, die Pollin anbietet, ist eigentlich die
Rede? Und was ist nun falsch?
>Datentransfer:>Daten auf den Datenport DB0-7 schreiben>D/I je nach Transferart auf high (Daten) oder low (Kommando) setzen und>R/W je nach Wunsch auf high (read from display) oder low (write to>display) setzen>E auf high ziehen>8-10 nops>CS1/2 (nach Belieben) auf high ziehen (high = aktiv)>8-10 nops>E auf low ziehen>8-10 nops>CS1/2 auf low ziehen>8-10 nops
Die TC12864 Displays haben anscheinend KS108 (-kompatible) Controller.
Der fordert für einen E-Impuls (Low/High) 1µs. Da braucht es garantiert
keine drei mal 8 Nops für ein richtiges Timing.
MfG Spess
@Icke: OK, ich hab selber schon Posts mit sehr viel längerem (in-line)
Code gelesen und zumindest verstanden (wenn auch nicht den Fehler
gefunden), anscheinend haben sich auch andere die Mühe gemacht und dann
sinnvoll geantwortet, ganz abwegig ist es daher nicht... aber klar, das
kann ich zukünftig besser machen. Schön ist es trotzdem nicht, wenn ich
dann nachfrage(!) und dann immer noch keine konstruktive Antwort kommt.
Ein kurzes "zuviel Code" hätte ja gereicht.
Natürlich ist es Zufall, dass mein Code beim m8A funktioniert hat --
rückblickend verstehe ich nicht mal, wie er überhaupt funktionieren
konnte, ich hab ja mit "low-active" programmiert... Das war eins meiner
Probleme, weshalb ich gepostet hatte... weil ich selber nicht
weitergekommen bin. Wie man komplexe Probleme dieser Art auf weniger
Info runterbrechen kann, wüsste ich jetzt nicht.
--------
Hi Spess,
mein Gedächtnis hat mich getrogen (Entschuldigung!), nicht die
Pollin-Datenblätter für das B-03 und B-05 sind falsch (die enthalten gar
keine Programmier-Info, was mich damals schon geärgert hat), sondern das
Tinsharp-Datenblatt, das für die Ansteuerung des TG12864B-03
"low-active"-Timingdiagramme anzeigt; sonst hab ich nirgendwo sinnvolle
Doku dazu gefunden. Hätte ich bei Pollin ins Datenblatt zum TG12864B-13B
geschaut, hätte ich vielleicht draufkommen können, aber eher nicht...
Auch ist der hier im Forum bei Problemen mit den 128x64-Displays immer
wieder gelesene Verweis auf das KS0108B-Datenblatt irreführend, das
dieselben low-active-Timings hat. Für mich klingt das nach "Ach, der
wollte sich einfach nicht die Mühe machen, die ich mir damals gemacht
hab, ich speis' den einfach mit irgendeinem unsinnigen Kommentar ab"...
Was mich frustriert hat, war, dass die Lösung so unendlich einfach ist
und es hier trotzdem etliche unbeantwortete Fragen zu diesem Display
gibt, oft auch völlig ignorierte Threads (wie meiner, der erst bevölkert
wird, wenn ich kritisch werde). Wozu ist ein Forum da, wenn man nur
Fragen stellen darf, die sich nach Lesen des Datenblatts nicht
erübrigen, aber damit den meisten schon zu weit gehen?
Essentiell war die Lösung des Problems jetzt auch nicht (wie hier so oft
als Dogma präsentiert) das Lesen des (inkorrekten bzw. nicht findbaren)
Datenblatts, sondern reines statistisches Ausprobieren... Natürlich ist
Datenblattlektüre sinnvoll, aber unter "Hilfe" verstehe ich auch, dass
man anderen den Verständnisweg abkürzt, der einen selber viel Zeit
gekostet hat. Nicht immer ist "selber machen" die beste Antwort... aber
es ist oft (und gerade unter Elektroingenieuren anscheinend akzeptiert)
die bequemste.
Gruss,
Eingehirner
P.S.:
Es ist richtig, dass im Datenblatt was von 1000ns für einen minimalen
E-Zyklus steht (entspricht bei 8MHz acht Takten). Effektiv hat bei mir
alles unter sieben "nops" aber trotz kurzer Leitungen und der
zusätzlichen Zeit durch das "sbi" zu Datenverlusten beim Schreiben
geführt (Pixelfehler, unbeschriebene Blöcke etc), deshalb die acht
"nops". Das reicht immer noch für eine Wiederholfrequenz, die weit über
allem liegt, was ich damit machen will. Vermutlich lassen sich einige
davon wegoptimieren (speziell die letzten zwei Blöcke sind wohl
unnötig), um die Geschwindigkeit nochmal zu steigern. Werde es
ausprobieren und hier posten (diesmal dann als Anhang). Ich will ja
nicht die Fehler machen, die ich anderen ankreide.
Gruss,
Eingehirner
Hi
>Auch ist der hier im Forum bei Problemen mit den 128x64-Displays immer>wieder gelesene Verweis auf das KS0108B-Datenblatt irreführend, das>dieselben low-active-Timings hat.
Ich verstehe immer noch nicht, wo du den 'Fehler' gefunden haben willst.
Werde doch mal konkret. Was ist bei dir 'low-active-Timing'?
MfG Spess
Datenübertragung an den KS0108B wird im Datenblatt folgendermassen
formuliert:
"In order to interface data for input or output The terminals have to be
CS1B=L, CS2B=L and CS3=H." (S.4)
und
"write mode (R/W=L) -> data of DB<0:7> is latched at the falling edge of
E." (ebda.)
Da hier bei Problemen mit 128x64-Displays immer direkt auf diesen
Controller verwiesen wird, liegt die Vermutung nahe, dass die
Beschaltung von CS1(B), CS2(B) und E identisch ist, was -- zumindest
nach meinem jetzigen Kenntnisstand -- nicht richtig ist. Das
Tinsharp-Datenblatt ist diesbezüglich irreführend, weil es für das
Display die Timing-Diagramme des KS0108B angibt (S.6).
Das TG12864B-03 funktioniert in meiner Schaltung jedenfalls genau
umgekehrt: Wenn E=H ist, werden Daten mit "rising edge" von CS1/2
übertragen. E kann für ausschliessliches Schreiben (ohne Prüfen des
"Busy"-Flag oder Auslesen des Display-RAM) dauerhaft auf H liegen. In
der Hinsicht reagiert es ähnlich wie das LCD12232 von Pollin.
Gruss,
Eingehirner