;****************************************************************************
;* *
;* LCD Controller für Dualscan 640x480 LCD *
;* *
;****************************************************************************
;* *
;* Einfacher LCD Controller für ein SW 640x480 LCD, wie es in vielen alten *
;* Notebooks verbaut ist. *
;* Außer einem mega8515, einem 74HC32, dem 74x573 Adresslatch im Datenbus, *
;* und einem 64kB SRAM (mit 55ns oder schneller) werden keine weiteren *
;* Bauteile benötig. Neue Daten werden über RS232 mit 115200Baud in den *
;* Speicher geladen. Allerdings kann man auch jedes andere Interface wie *
;* z.B. SPI verwenden, solange dafür nicht zuviel Rechenzeit benötigt *
;* wird. Immerhin müssen (mehr oder weniger) kontinuierlich 2,5MB/s *
;* ausgegeben werden ! Damit das ganze problemlos funktioniert, läuft der *
;* AVR mit 18,432MHz und steuert das LCD mit rund 65Hz an. *
;* *
;* Der Datentransfer über RS232 behindert die Datenausgabe auf dem LCD *
;* nicht, man sieht also keinm Flackern oder ähnliches. Nur beim Löschen *
;* von Zeilen muss man aufpassen: Es dauert sehr viel länger, eine Zeile *
;* zu löschen und das LCD anzusteuern, als den nächsten Befehl zu senden *
;* Hier kommt es kurz zu einem Flackern, wenn man viele Löschbefehle *
;* direkt hintereinander sendet. Dafür lässt sich das LCD aber in sehr *
;* kurzer Zeit Zeilen weise löschen. *
;* *
;* Die Datenübertragung läuft über den UART, der im 9bit Modus betrieben *
;* wird. Das 9.Bit entscheidet zwischen Daten und Befehl. Ist es gesetzt, *
;* handelt es sich um ein Befehl, ist es gelöscht dann wird der Wert als *
;* Daten oder als Parameter eines zuvor gesendeten Befehls behandelt. *
;* *
;* Befehle: *
;* *
;* 001 Set Cursor. Gefolgt von zwei Parametern, nämlich der Zeilen *
;* und Spaltenadresse. Die Zeilenadresse liegt im Bereich 0-239, *
;* und die Spaltenadresse im Bereich 0-79 (plus 128, falls die *
;* Position in der unteren Displayhälfte liegt.) *
;* *
;* 010 Clear Line. Dieser Befehl benötigt keinen Parameter und löscht *
;* die aktuelle Zeile. Danach wird der Cursor auf den Beginn der *
;* nächsten Zeile gesetzt. So kann man 480 mal diesen Befehl *
;* senden, um das ganze LCD zu löschen. Allerdings ist dieser *
;* Befehl sehr komplex, und benötigt daher einiges an Zeit. Sendet *
;* man also diesen Befehl öfters ohne Pause, dann kommt es zu *
;* einem kurzen Flackern des LCDs. *
;* *
;* 011 Clear LCD. Dieser Befehl löscht das LCD in extrem kurzer Zeit. *
;* Aber wie auch schon beim Clear Line Befehl, benötigt er einiges *
;* an Zeit um den kompletten Speicher zu löschen. Das LCD Timing *
;* wird zwar nicht ganz eingehalten, aber man merkt nichts davon. *
;* *
;* Daten: Nach dem Senden eines Datenwertes wird dieser in den Speicher *
;* geschrieben, und der Adresszähler anschließend erhöht. *
;* Jedes Byte enthält 8 nebeneinanderliegende Pixel. Im SRAM *
;* werden dagegen 4 nebeneinander liegende Pixel aus der oberen, *
;* und 4 nebeneinander liegende Pixel aus der unteren Hälfte *
;* gespeichert. Das mach das Laden von Daten etwas komplizierter, *
;* vereinfacht und beschleunigt die Ausgabe extrem. *
;* *
;* IO Pins: *
;* *
;* *
;* PD0 RXD RS232 Dateneingang *
;* PD3 EXSCL Aktivierung für XSCL. Dieser Pin aktiviert über ein *
;* 74HC32 den Schiebetakt für die Daten *
;* PD4 LP Latchpuls. Der Impuls läd die Daten aus dem Schiebe- *
;* register ins Display. Dient als HSync. *
;* PD5 FLM VSync für das LCD. Das LCD springt in die erste Zeile. *
;* PD6 WR\ Write Enable für das SRAM. *
;* PD7 RD\ Output Enable für das SRAM und XSCL über den 74HC32 *
;* für das LCD. Bei jedem Lesevorgang werden die Daten ins *
;* LCD geladen *
;* PB0 EnLCD Schaltet über einen PNP und einen PNP Transistor die *
;* LCD Spannung, damit im Falle eines Fehlers (z.B. Ausfall*
;* der +5V) das LCD nicht zerstört wird. *
;* PB1 Busy Zeigt durch einen High Pegel an, ob der uC mit dem Laden*
;* von Daten oder Ausführen von Befehlen beschäftigt ist. *
;* Da das Laden von Daten schneller geht, als das Senden *
;* eines Wertes, braucht man Busy eigentlich nur bei den *
;* Clear Line und Clear LCD Befehlen abzufragen. *
;* *
;****************************************************************************
.include "m8515def.inc" ;@18,432MHz
.def null=r0
.def eins=r1
.def temp =r16
.def temp2 =r17
.def temp3 =r18
.def Bits =r19
.def NextOp =r20 ;Zähler für Parameter eines Befehls
.def tempm =r21
.def Flags =r22
.def XAdresseLow=r26 ;Writepointer Spalte
.def ZeileL =r27 ;Writepointer Zeile LSB
.def AdresseLow =r30 ;Readpointer Spalte
.def AdresseHigh=r31 ;Readpointer Zeile
;PortB
.equ EnLCD =0 ;LCD Spannung einschalten
.equ Busy =1
;PortD
.equ XSCL =3 ;Enable XSCL
.equ LP =4 ;HSync
.equ FLM =5 ;VSync
;Flags
.equ Frame =0 ;Warten bis 1/(60fps * 242 Zeilen) Sekunden vorbei ist, ehe die nächste Zeile ausgegeben wird.
.equ ZeileH =7 ;Writepointer Zeile MSB, entscheidet zwischen obere und untere Displayhälte, also zwischen Hig und Low Nibble eines RAM Bytes
.org 0000
rjmp reset
.org OVF0addr ;Timer 0
rjmp Framestart
.org URXCaddr ;Interruptvektor für UART-Empfang
rjmp RXRoutine
.org 32
reti
Framestart:
out Tcnt0, tempm
sbr Flags, (1< Max ?
brne normal
clr XAdresseLow ;Spalten Adresse = 0
inc ZeileL ;Zeilen Adresse ++
cpi ZeileL, 244 ;Zeilen Adresse in untere Displayhälfte ?
brne normal
ldi ZeileL, 4 ;Zeile = Beginn XRAM
sbr Flags, (1< Max ?
brne normal
clr XAdresseLow ;Spalten Adresse = 0
inc ZeileL
cpi ZeileL, 244 ;Zeilen Adresse in untere Displayhälfte ?
brne normal
ldi ZeileL, 4 ;Zeile = Beginn XRAM
cbr Flags, (1<