8-Bit-Breadboard-Computer auf Basis einer 6502-CPU - 3x16 Zeichen Anzeige mit DOGM163 LCD - Debugging

Bisherige Artikel dieser Serie - hier könnt ihr nochmal alle Grundlagen nachlesen, falls ihr jetzt erst einsteigt: Im letzten Teil hatte wir ja bereits unser neues IO-Gerät, eine 48 Zeichen fassende LCD-Anzeige auf dem Bredboard aufgebaut und eine erste Programmversion geschrieben.

Nur leider funktionierte die erste Version des Programmes - wie das so häufig ist - nicht auf Anhieb. Jetzt ist die große Frage: liegt der Fehler in der Hardware oder in der Software?

Ich habe schon ein paar Erfahrungen mit dem DOGM163-Display gemacht, z. B. mit einem STM32, 3.3V und SPI und weiß das es ein wenig tückisch ist.

Klugerweise habe ich im Vorfeld den für mich neuen 4-Bit-Modus schon einmal mit dem Arduino getestet und dabei festgestellt, dass die Initialisierungs-Sequenz im Datenblatt nicht stimmen kann; denn wenn ich diese verwende, bleibt das Display einfach nur dunkel. Auf dem Arduino und mit C stehe ich auf ein wenig festeren Füßen als mit einer selbst entworfenen Breadboard-Schaltung mit 6502 CPU und eigener IO-Architektur.

Darum war das keine schlechte Idee, die Hardware erst einmal unter Arduino zum Laufen zu bringen. Und nach längerer Tüftelei ist es mir dann auch gelungen, das Display unter 5V und im 4Bit-Modus zum laufen zu bringen.

Sonst nämlich hätte ich mich eventuell auf die Angaben im Datenblatt verlassen und den Fehler ewig in der Breadboard-Schaltung gesucht und dort natürlich nicht gefunden, weil er halt in der Display-Ansteuerung liegt.

Trotzdem könnte ich natürlich das Display immer noch falsch verkabelt haben. Ich müsste nur eine Datenleitung vertauscht haben und schon wären die Bits durcheinander und es kämen unsinnge Befehle beim Display an. Evtl. taktet der 74HC138 nicht richtig auf der neu verwendeten Leitung? Der Möglichkeiten für Fehlerquellen gibt es viele.

Da ich aber besondere Sorgfalt beim Verdrahten habe walten lassen und die Verkabelung vom Arduino quasi kopieren konnte und ich ehrlicherweise gerade keine Lust auf stupides Durchmessen hatte, wollte ich mir doch zuerst einmal den Source noch einmal genauer anschauen, ob nicht da ein Fehler ist.

Schon als ich den Code noch einmal in Ruhe durchging, fand ich den ersten Fehler. Das EPROM-Image wurde neu gebrannt und die neue Version ausgetestet, aber das Display blieb schwarz.

Also im Code einmal ein STP an der Stelle, wo das Datenbyte an das Display geschickt wird, eingebaut und am Breadboard-Computer den integrierten Bus-Sniffer aus Arduino Basis benutzt, um mir anzuschauen, was da genau vor sich ging. Und dabei einen weiteren Fehler gefunden: Ich hatte ein BRA, einen Sprung vergessen. Wieder: an den PC, Source ändern, EPROM neu brennen, wieder in den Breadboard-Computer einsetzen und neu testen.

Noch stand nichts auf dem Display, also beschließe ich, die auf dem Breadboard integrierte 8-LED-Ausgabe zu benutzen, um dort das Datenbyte, das zum LCD geschickt wird zu setzen. Das macht das Debuggen einfacher. Ich muss nicht Befehl für Befehl auf der Sniffer-Anzeige durchschauen, sondern kann erst einmal grob die LEDs beobachten. Das geht viel schneller. Später, wenn der Fehler eingegrenzt ist, kann ich ja dann wieder feingranularer auf dem Sniffer nachschauen. So stelle ich den Takt auf ein Tempo, wo ich noch alles mitbekomme und lasse das Programm laufen.

Die LED für die Reset-Leitung ist immer an. Reset ist also immer auf high. So soll es sein. Auch die Schreib-Leitung ist immer auf low - es wird ja nur geschrieben - auch das ist richtig. Und die 4 Bits der Nibbles scheinen auch in der richtigen Reihenfolge zu sein. Wunderbar. Alles richtig verdrahtet.

Doch dann fällt mir auf, dass Enable nicht gepulst wird. Ein Bick auf den Source und mir fällt auf, dass ich beim pulsen einen STA absetzen, ohne vorher einen LDA gemacht zu haben. Dummer Fehler. Aber passiert. Das EPROM wieder gebrannt und neu getestet.

Noch immer ist das Display dunkel... doch halt. Beim ganz genau hinschauen kann ich schwach Buchstaben auf dem Display erkennen. Dort steht doch tatsächlich "HELLO WORLD". So ein hinterhätiges Display; böser Hund! (kleiner Wortwitz wegen DOG). Doch statt mich über das Display zu ärgern, dass es scheinbar bei 5 Volt auch hier den Kontrast nicht konstant hinkriegt (also war der Arduino bei meinen Tests vorher nicht schuld) überwiegt die Freude, dass es doch läuft.

Beim nächsten Lauf ist auch der Kontrast besser. Na, wo es jetzt läuft, kann die Lichtorgel ja wieder aus, denn die LED-Debug-Anzeige brauche ich jetzt ja nicht mehr. Das sollte die Ausgabe auch noch ein bisschen schneller machen. Denn man kann locker und leicht mitlesen, so langsam ist die Ausgabe bei der momentanen Höchstfrequenz von 500 Hertz.

Video

Ich habe auch diesmal wieder ein Video gemacht, dass nur wenig geschnitten ist und in dem ihr sozusagen live mitverfolgen könnt, wie ich beim Debuggen vorgegangen bin:



Source-Code

Damit ist das Assembler-Programm jetzt fehlerfrei und fertig und ich will es euch nicht weiter vorenthalten.

6-DOGM163-LCD-Ausgabe.asm (klicken, um diesen Abschnitt aufzuklappen)
; Einschaltmeldung auf DOGM163-LCD ausgeben ; last edit: Oliver Kuhlemann (www.cool-web.de), 2020-08-10 CHIP W65C02S ; (default) ORG $8000 ; Programmstartadresse (von der CPU aus gesehen) ; --- Konstanten: IO-Adressen --- LED: equ $7000 ; 8-LED-Ausgabe SEGL: equ $7001 ; linke 7-Segment-Anzeige SEGM: equ $7002 ; mittlere 7-Segment-Anzeige SEGR: equ $7003 ; rechte 7-Segment-Anzeige LCD: equ $7004 ; DOGM163 LCD mit 3*16 Zeichen ; --- Kontanten: Bitpositionen --- bitLCD_Reset: equ 1 ; Bit 0 = Reset (0) / normal (1) bitLCD_RS: equ 2 ; Bit 1 = RS = Command (0) / Character (1) bitLCD_RW: equ 4 ; Bit 2 = RW = Write (0, normal) / Read (1, nicht benutzt) bitLCD_E: equ 8 ; Bit 3 = Enable (pulse=1, normal=0) ; bit 4 bis 7 = Datenbits D4 bis D7 ; --- Konstanten für LCD opLCD_Clear: equ %00000001 opLCD_Home: equ %00000010 opLCD_DispOn: equ %00001100 opLCD_DispOff: equ %00001000 opLCD_CursorOn: equ %00001111 opLCD_CursorOff: equ %00001100 ; --- Speicheradressen RAM lcdhb: equ $00 lcdlb: equ $01 lcdrs: equ $02 ; 1= char, 0= cmd, vor jsr lcdByte setzen init: ; LED-Ausgabe löschen lda #0 sta LED ; Segment-Ausgabe löschen lda #$FF sta SEGL sta SEGM sta SEGR init_LCD: ; Reset an LCD (Bit 0 auf Low für ein paar ms) lda #0 sta LCD lda #5 jsr delay ; wieder auf high und min 50 ms warten lda #1 sta LCD lda #15 jsr delay jsr lcdInit start: ldx #0 print: ldy HELLO,x ; X. Buchstaben aus "HELLO WORLD" in Y-Register laden beq fertig lda #1 ; ist ein zeichen sta lcdrs tya jsr lcdByte inx bra print fertig: stop: STP ; Hält die CPU an ; --- Unterprogramme --- delay: NOP ; Zeit verschwenden, NOP = 2 Taktzyklen NOP dec A bne delay rts ; --- für LCD --- INCLUDE lcd.inc ; --- im ROM abgelegte Konstanten HELLO: ; 1234567890123456 Spaces am Ende gelten auch, auch wenn man sie nicht sieht ASCII 6502 Breadboard ASCII Retro Computer ASCII www.cool-web.de BYTE 0 INCLUDE seg-defs.inc ; --- Sprungvektoren ORG $FFFA word $8000 ; NMI bei $FFFA/B word $8000 ; Programmstartadresse bei $FFFC/D word $8000 ; BRK/IRQ bei $FFFE/F
lcd.inc (klicken, um diesen Abschnitt aufzuklappen)
; Unterprogramme für DOGM163-LCD ; last edit: Oliver Kuhlemann (www.cool-web.de), 2020-08-09 lcdByte: ; Übergabe Bytewert in Akku, Command (0) / Character (1) in lcdrs sta lcdhb ; Übergabe aus Akku speichern -> Highbyte kommt zuerst dran sta lcdlb ; Übergabe aus Akku speichern -> schon mal Lowbyte speichern asl lcdlb ; unteren 4 Bit nach links nach oben schieben asl lcdlb asl lcdlb asl lcdlb smb0 lcdhb ; Reset aus smb0 lcdlb rmb2 lcdhb ; Write rmb2 lcdlb rmb3 lcdhb ; Enable erst einmal auf low rmb3 lcdlb ; command (lcdrs=0) oder Character (lcdrs=1) lda lcdrs bne lcdByteCmd rmb1 lcdhb ; Command (0) / Character (1) rmb1 lcdlb ; Command (0) / Character (1) bra lcdByteCmd_after lcdByteCmd: smb1 lcdhb ; Command (0) / Character (1) smb1 lcdlb ; Command (0) / Character (1) lcdByteCmd_after: ; High-Byte übertragen und pulsen (E-Leitung auf High für ein paar ms, min. 2 ms) lda lcdhb sta LCD ;sta LED nop smb3 lcdhb ; E-Leitung kurz auf High pulsen lda lcdhb sta LCD ;sta LED nop rmb3 lcdhb ; E-Leitung wieder auf Low lda lcdhb sta LCD ;sta LED nop ; Low-Byte übertragen und pulsen (E-Leitung auf High für ein paar ms, min. 2 ms) lda lcdlb sta LCD ;sta LED smb3 lcdlb ; E-Leitung kurz auf High pulsen lda lcdlb sta LCD ;sta LED nop rmb3 lcdlb ; E-Leitung wieder auf Low lda lcdlb sta LCD ;sta LED nop rts lcdInit: ; LCD initialisieren -------------------------------------------------------------- ; 8-Bit-Mode einschalten; nötig, um nach deinem Reset die Spur wieder zu finden lda #0 ;cmd sta lcdrs lda #%00110000 jsr lcdByte ; nötig, um nach deinem Reset die Spur wieder zu finden lda #0 ;cmd sta lcdrs lda #%00110011 jsr lcdByte ; nötig, um nach deinem Reset die Spur wieder zu finden lda #0 ;cmd sta lcdrs lda #%00110010 jsr lcdByte ; 4-Bit-Mode einschalten; extended instruction table 1 setzen lda #0 ;cmd sta lcdrs lda #%00101001 jsr lcdByte ; bias set lda #0 ;cmd sta lcdrs lda #%00011101 jsr lcdByte ; Power/ICON control/Contrast set lda #0 ;cmd sta lcdrs lda #%01010011 jsr lcdByte ; Follower control lda #0 ;cmd sta lcdrs lda #%01101111 jsr lcdByte ; Contrast set(low byte) lda #0 ;cmd sta lcdrs lda #%01111111 jsr lcdByte ; es folgen nur noch Standard-Befehle: normal instruction table lda #0 ;cmd sta lcdrs lda #%00101000 jsr lcdByte ; Entry Mode Set lda #0 ;cmd sta lcdrs lda #%00000110 jsr lcdByte ; clear lda #0 ;cmd sta lcdrs lda #opLCD_Clear jsr lcdByte ; display on lda #0 ;cmd sta lcdrs lda #opLCD_DispOn jsr lcdByte rts




Sonstige Problemchen mit dem LCD

Scheinbar mag das DOGM163 nicht immer hundertprozentig mit 5V und ohne Booster-Kondensatoren laufen. Das war mir ja schon bei den Tests mit dem Arduino aufgefallen, dass der Kontrast bzw. die Helligkeit schwankt.

Auch habe ich festgestellt, dass unten beim Display nur noch vier der fünf Volt Versorgungsspannung ankommen. Das was am meisten Strom zieht, dürfte der Sniffer sein. Den brauche ich auch nicht immer und habe deshalb für ihn einen Schalter nachgerüstet und ihn abschaltbar gemacht. Zudem habe ich statt der Drahtbrücke für die Hintergrundbeleuchtung einen 100 Ohm Widerstand eingesetzt, damit die Hintergrundbeleuchtung des Sniffer-Displays nicht die des DOGM163 überstrahlt, wenn es denn an ist.

Das DOGM163 ist ganz gut ablesbar (wenn ich nicht mal wieder gerade spinnt), wenn man davor sitzt, aber auch der Kamera kommt es nicht so deutlich rüber wie etwa das Nokia 5110 Display. Aber die Kamera-Tüchtigkeit soll jetzt nicht oberste Priorität sein; zur Not lese ich euch dann in zukünfitgen Videos einfach vor, was auf dem DOGM163 steht.

Aussichten

Die Ausgabe auf das LCD könnte ein bisschen schneller vonstatten gehen. Für den nächsten Teil will ich mal schauen, wie ich die Taktfrequenz so erhöhe, dass ein Mitlesen gut möglich, aber nicht zu langsam ist. Entweder über das NE555-Clockmodul oder indem ich den Frequenzgenerator einsetze. Das Timing, also die Pausen, für das LCD werde ich dann natürlich auch noch entsprechend anpassen müssen.