;**************************************************************************** ;* * ;* LCD Controller für Dualscan 640x480 LCD * ;* * ;* Serieller Datenbus * ;* * ;* Version 0.21 * ;* * ;* © by Benedikt * ;* * ;* Email: benedikt83 ät gmx.net * ;* * ;**************************************************************************** ;* * ;* Die Software darf frei kopiert und verändert werden, solange sie nicht * ;* ohne meine Erlaubnis für kommerzielle Zwecke eingesetzt wird. * ;* * ;**************************************************************************** ;* * ;* Einfacher LCD Controller für ein SW 640x480 LCD, wie es in vielen alten * ;* Notebooks verbaut ist. * ;* Außer einem mega8515, einem 74x02, dem 74x573 Adresslatch im Datenbus, * ;* und einem 64kB SRAM (mit 55ns oder schneller) werden keine weiteren * ;* Bauteile benötig. Neue Daten werden über ein paralleles Interface mit * ;* bis zu 150kByte in den Speicher geladen. * ;* Aufgrund der hohen Datenrate des Parallelports und der LCD Ausgang, * ;* läuft der AVR mit 16,000MHz und steuert das LCD mit rund 60Hz an. * ;* * ;* 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.) * ;* * ;* 002 Set PWM. Stellt das Tastverhältnis des PWM Ausgangs OC1B ein. * ;* Das Tastverhältnis folgt auf diesen Befehl als Parameter. * ;* * ;* 003 Set X Start. Stellt den Startwert für den Zeilenbeginn ein. * ;* Damit lässt sich ein Ausschnitt aus dem virtuellen 1000x480 * ;* Bild im Speicher auf dem LCD anzeigen. * ;* * ;* 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, * ;* da ab und zu dummy Daten ans LCD gesendet werden. * ;* * ;* 192 Display Character. Mit diesem Befehl wird ein ASCII Zeichen * ;* mittels des interenen Character Generator dargestellt. Das * ;* gewünschte Zeichen wird als Parameter übergeben. Die * ;* Darstellung erfolgt als 8x8 Zeichen. Die Schriftart entspricht * ;* der auf einem PC im 640x480 Grafikmodus. * ;* * ;* 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 aber extrem. * ;* * ;* IO Pins: * ;* * ;* PA0-7 Adr/Dat Daten/Low Adresse für den SRAM * ;* PC0-7 Adresse High Adresse für den SRAM * ;* PD0 RXD UART: RXD * ;* PD1 Busy UART: CTS, Busy=high, Ready=low * ;* PD3 EXSCL Aktivierung für XSCL. Dieser Pin aktiviert über ein * ;* 74HC02 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 VWR\ Write Enable für den SRAM. * ;* PD7 VRD\ Output Enable für den SRAM und XSCL über den 74HC32 * ;* für das LCD. Bei jedem Lesevorgang werden die Daten ins * ;* LCD geladen * ;* PE0 EnLCD Schaltet über einen PNP und einen NPN Transistor die * ;* LCD Spannung, damit im Falle eines Fehlers (z.B. Ausfall* ;* der +5V) das LCD nicht zerstört wird. * ;* PE1 ALE Adress Latch für Low Adressen des SRAMs * ;* PE2 PWM PWM Ausgang, z.B. für Displaykontrast * ;* * ;**************************************************************************** .include "m8515def.inc" ;@16,000MHz .def null =r0 .def eins =r1 .def voll =r2 .def regsave=r3 .def tempm =r4 .def XStart =r5 ;Beginn einer Spalte ab Nibble .def XScan =r6 ;Endadresse bei der Bildausgabe in X Richtung .equ XSize =160 ;Bildgröße in X Richtung in Nibbles .equ YSize =200;240 ;Bildgröße in Y Richtung pro Halbbild .equ XOScan =0 ;Anzahl der zusätzlich auszugebenden Nibbles in X Richtung .equ YOScan =2 ;Anzahl der zusätzlich auszugebenden Zielen in Y Richtung (muss >=2 sein, sonst geht z.B. das Pollin LCD kaputt !) .equ YScan =YMin+YSize+YOScan ;Endadresse bei der Bildausgabe in Y Richtung .equ XMax =250 ;Maximale Speicheradresse in XRichtung .equ YMin =4 ;Minimale Speicheradresse in Y Richtung .equ YMax =YMin+YSize ;Maximale Speicheradresse in Y Richtung .def temp =r16 .def temp2 =r17 .def temp3 =r18 .def NextOp =r19 ;Zähler für Parameter eines Befehls .def Flags =r20 .def XAdresseLow=r26 ;Writepointer Spalte .def ZeileL =r27 ;Writepointer Zeile LSB .def AdresseLow =r28 ;Readpointer Spalte .def AdresseHigh=r29 ;Readpointer Zeile ;PortB ; 8bit IO Data .equ LCDon =0 ;LCD ein/ausschalten ;PortD .equ RXD =0 ;Command/Data .equ Busy =1 ;Controller Busy ;.equ WR =2 ;Write Data: min. 1us Low .equ XSCL =3 ;Enable XSCL .equ LP =4 ;HSync .equ FLM =5 ;VSync ;PortE .equ EnLCD =0 ;LCD Spannung ein/ausschalten ;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 High und Low Nibble eines RAM Bytes ;NextOPs .equ SetCurL =1 .equ SetCurH =2 .equ SetPWMV =3 .equ CGChar =4 .equ SetScroll =5 .equ Escape =14 .equ CD =7 .equ YPos =190 ;Position des Logos .equ XPos =200 ;Position des Logos .equ FrameFreq =60 ;Bildwiederholfrequenz .equ TReload = 256-(2000000/FrameFreq/(YSize+YOScan)) ;Reloadwert für Timer .org 0000 rjmp reset .org OVF0addr ;Interruptvektor für Beginn von neuer Zeile (Display Timing) rjmp HSync .org URXCaddr ;Interruptvektor für Daten-Empfang in temp, udr ;Daten von PORTB lesen rjmp Write .org 32 reti HSync: sbrc Flags, Frame ;Wurde letze Zeile überhaupt ausgegeben, oder hat Datentransfer alles blockiert ? sbi portd, Busy ;Wenn ja, dann Busy Pin setzen (ist zwar nicht unbedingt notwndig, verbesser aber das Display Timing=weniger Flimmern) out Tcnt0, tempm ;Timerwert laden sbr Flags, (1< NextOp.Escape setzen. out sreg, regsave reti ;*** Bearbeitung der Daten *** Daten: cpi NextOp, 0 ;Paramter oder Daten ? brne Next sbi portd, XSCL ;Datenverbindung zum LCD unterbrechen sbrc Flags, ZeileH ;Pixel in der oberen oder unteren Displayhälfte ? rjmp untereHalfte obereHalfte: ld temp2, X ;Lader Wert aus SRAM andi temp2, 15 ;obere Datenhälfte der SRAM Daten behalten mov temp3, temp andi temp3, 240 ;erste Hälfte der Daten behalten or temp2, temp3 ;Beide Hälften zusammenfügen st X+,temp2 ld temp2, X andi temp2, 15 ;obere Datenhälfte der SRAM Daten behalten swap temp andi temp, 240 ;zweite Hälfte der Daten behalten or temp2, temp st X+,temp2 cpi XAdresseLow, XMax ;Spalten Adresse > Max ? brlo normal clr XAdresseLow ;Spalten Adresse = 0 inc ZeileL ;Zeilen Adresse ++ cpi ZeileL, YMax ;Zeilen Adresse > Max ? brlo normal ldi ZeileL, YMin ;Zeile = Beginn XRAM sbr Flags, (1< Max ? brlo normal clr XAdresseLow ;Spalten Adresse = 0 inc ZeileL cpi ZeileL, YMax ;Zeilen Adresse > Max ? brlo normal ldi ZeileL, YMin ;Zeile = Beginn XRAM cbr Flags, (1< Max ? brne normal2 clr XAdresseLow ;Spalten Adresse = 0 subi ZeileL, -8 ;Zeilen Adresse ++ cpi ZeileL, YMax ;Zeilen Adresse > Max ? brlo normal2 ldi ZeileL, YMin ;Zeile = Beginn XRAM ldi temp, (1<Bit3 ? Dann im nächsten Byte lesen inc XAdresseLow andi temp2, 3 ;zu löschendes Bit (Bit 0-39 clr temp3 clc inc temp2 ser temp3 pow: rol temp3 dec temp2 brne pow ;temp3 enthält nun (1<