/* Modul gdriver.c Dieses Modul stellt Routinen zur Ansteuerung des grafischen 320x240 Display Controllers von Benedikt Kullmann auf Basis eines ATMega bereit. Steuerprotokoll siehe pdf Datei. Es wird die Uart 1 benutzt Der Empfangspuffer wird nicht benutzt, da der Display Controller nichts ausgibt. Beispiel Schreibvorgang: sprintf(gdisp_buf," "); String in Buffer schreiben UART1_Write(); Uart betätigen Benutze Pins: P2.0 = TXD1 P2.1 = RXD1 P2.2 = Controller Busy */ #include #include #include "LPC23xx.h" #include "config.h" #include "timer.h" #include "comm.h" #include "irq.h" #include "rtc.h" #include "gdriver.h" ////////////////////////////////////////////////////////////////////////////////////////// // Globale Public Variablen ////////////////////////////////////////////////////////////////////////////////////////// // Der sprintf Puffer in welchen geschrieben wird uint8_t gdisp_buf [41]; // Der Zeichenpuffer das Display hat 40 x 20 Zeichen = 800 Zeichen uint8_t GD_CharBuf[MAX_LINE][MAX_LPOS+1] __attribute__ ((section(".usbram"))); ////////////////////////////////////////////////////////////////////////////////////////// // Externe Variablen ////////////////////////////////////////////////////////////////////////////////////////// extern uint8_t gdisp_buf []; ////////////////////////////////////////////////////////////////////////////////////////// // interne globale Variablen ////////////////////////////////////////////////////////////////////////////////////////// // Die TX/RX Fifo Puffer werden ins USB RAM gelegt static struct rx_fifo Tx1Fifo __attribute__ ((section(".usbram"))) ; static struct tx_fifo Rx1Fifo __attribute__ ((section(".usbram"))) ; static uint32_t Tx1Run = 0; // 1 = Transmission aktiv //////////////////////////////////////////////////////////////////////////////////// /* Funktion: Isr_UART1 (void) Typ : ISR Modul : gdriver.c -------------------------------------------------------------------------------- Auswertung der IRQ Bits im U1IIR Register 0 IntStatus 1= Kein IRQ, 0 = IRQ 3:1 011 (3) 1 RLS (Receive Line status) +Errors: Overrung, Parity, Framing, Break IRQ 010 (2) 2a RDA (Receive Data available) +RX Fifo enthält Trigger Schwelle (U1FCR[7:6]) Zeichen 110 (6) 2b CTI (Character Time-out indicator) +RX FIFO enthält mindestens 1 Zeichen und 3-4 Perioden kein neues Zeichen 001 (1) 3 THRE Interrupt aufgerufene Funktionen : - Eingabeparameter : - Rückgabe : - veränderte Globals : TXRun0 Flag, RX Fifo, TX Fifo öffentlich/private : public letzte Änderung: 16.4.2009 */ ///////////////////////////////////////////////////////////////////////////////// void __attribute__ ((interrupt("IRQ"))) Isr_UART1 (void) { uint32_t d,zeichen, idx, cnt,int_stat, foo; // Wiederhole solange Pending IRQ anliegen while (1) { // Liegen IRQs an? (das U1IIR Register verändert sich beim Lesen!) int_stat = U1IIR; if (int_stat & UIIR_PEND) goto exit_isr; int_stat = (int_stat >> 1) & 0x07; // Pending IRQ Bit brauchen wir nicht mehr // ---- RLS (Receive Line status) (Es sind Fehler aufgetreten) if (int_stat == UIIR_RLS_INT ) { zeichen = U1LSR; // IRQ durch lesen löschen zeichen = U1RBR; // FIFO entleeren goto exit_isr; } // ---- RDA (Receive Data available) else if (int_stat == UIIR_RDA_INT) { idx = Rx1Fifo.wptr; cnt = Rx1Fifo.count; // Solange RX Fifo nicht leer ist... while (U1LSR & ULSR_RDR) { zeichen = U1RBR; // Zeichen aus Uart RX FIFO abholen if (cnt < BUFFER_UART1_SIZE) { // Im User RX FIFO speichern, solange nicht voll Rx1Fifo.buff[idx] = zeichen; cnt++; idx = (idx + 1) % BUFFER_UART1_SIZE; // Bei Fifo TOP rollen auf 0 } } } // ---- CTI (Character Time-out indicator) wird nicht beachtet else if (int_stat == UIIR_CTI_INT) { foo = U1LSR; // IRQ durch lesen löschen foo = U1RBR; } // ---- THRE Interrupt (Uart TX FIFO leer: U1LSR auslesen für weitere Infos) else if (int_stat == UIIR_THRE_INT) { // Hw TX FIFO wieder auffüllen cnt = Tx1Fifo.count; // Anzahl Zeichen im User TX FIFO holen if (cnt>0) { idx = Tx1Fifo.rptr; for (d = 12; d && cnt; d--, cnt--) { // Maximal 12 Zeichen im Hardware Fifo speichern U1THR = Tx1Fifo.buff[idx]; // Uart Hardware FIFO beschreiben idx = (idx + 1) % BUFFER_UART1_SIZE; // Bei Fifo TOP rollen auf 0 } // Fifo anpassen Tx1Fifo.rptr = idx; Tx1Fifo.count = cnt; } else Tx1Run = 0; // Run Flag löschen, wenn alle Daten gesendet } // was immer es auch sonst ist... else { foo = U1LSR; // IRQ durch lesen löschen foo = U1RBR; // FIFO entleeren } } exit_isr: VICVectAddr = 0; } //////////////////////////////////////////////////////////////////////////////////// /* Funktion: uart1_init Typ : normal Modul : gdriver.c -------------------------------------------------------------------------------- Beschreibung : Stellt die Uart1 ein, installiert die ISR Baudrate muss 28800 sein! aufgerufene Funktionen : install_irq Eingabeparameter : Baudrate Rückgabe : - veränderte Globals : - öffentlich/private : public letzte Änderung: 16.4.2009 */ ///////////////////////////////////////////////////////////////////////////////// void uart1_init (uint32_t baud) { uint32_t fdiv; PCONP |= (1 << 4); // Uart 1 einschalten // Pinsel Bits für UART1 Funktion setzen (Pinsel4 TXD1=1:0 RXD1=2:3 <- 10(0x02) einschreiben) PINSEL4 &= ~((0x03 << 0) | (0x03 << 2)) ; PINSEL4 |= ((0x02 << 0) | (0x02 << 2)); U1IER = 0x00; // Alle IRQ absschalten U1IIR; // IIR ID Register löschen U1RBR; // clear receive register U1LSR; fdiv = (F_apb / 16) / baud; // Baudrate etc einstellen U1LCR = 0x83; // divisor latch einschalten U1DLM = fdiv / 256; // set for baud low byte U1DLL = fdiv % 256; // set for baud high byte U1FDR = 0x10; // Fractional Divider ausschalten U1LCR = 0x03; // Format N81 setzen und divisor latch abschalten U1FCR = 0x07; // Uart FIFO ein (RX Triggerlevel 1 Zeichen) U1TER = 0x80; // TX einschalten // RX und TX FIFO löschen und initialisieren Tx1Fifo.rptr = 0; Tx1Fifo.wptr = 0; Tx1Fifo.count = 0; Rx1Fifo.rptr = 0; Rx1Fifo.wptr = 0; Rx1Fifo.count = 0; // Die ISR installieren install_irq (UART1_INT, (void*)Isr_UART1,LOWEST_PRIORITY); // alternativ: /* VICVectAddr28 = (uint32_t)&Isr_UART1; VICVectCntl28 = LOWEST_PRIORITY; VICIntEnable = 1 << UART1_INT; */ // RBR,THRE,RX Line Staus IRQs einschalten U1IER = UIER_ERBFI | UIER_ETBEI | UIER_ELSI; // IRQs einschalten } //////////////////////////////////////////////////////////////////////////////////// /* Funktion: uart1_put Typ : normal Modul : gdriver.c -------------------------------------------------------------------------------- Beschreibung : Gibt ein Zeichen auf uart1 aus aufgerufene Funktionen : - Eingabeparameter : - Rückgabe : - veränderte Globals : - öffentlich/private : private letzte Änderung: 25.5.2009 */ ///////////////////////////////////////////////////////////////////////////////// /* putchar Funktion von printf überschreiben: int __putchar(int ch) { return uart2_put (ch); } */ uint32_t uart1_put (uint8_t zeichen) { uint32_t idx,test; LED1_ON(); while BUSY_GET_IN(); // Warte ggf. bis UART den Buffer unter Schwelle geleert hat while (Tx1Fifo.count >= BUFFER_UART1_SIZE); U1IER &= 0x05; // UART THRE IRQs abschalten, Kollision vermeiden if (Tx1Run == 0) { // Falls keine ISR läuft, stosse sie an Tx1Run = 1; U1THR = zeichen; // UART mit Zeichen füllen, löst Uart IRQ aus. // falls Übertragung läuft schreibe nur in TX Fifo } else { idx = Tx1Fifo.wptr; // Schreibzeiger setzen Tx1Fifo.buff[idx] = zeichen; // Zeichen einschreiben Tx1Fifo.wptr = (idx + 1) % BUFFER_UART1_SIZE; // Fifo Schreibzeiger erhöhen/rollen Tx1Fifo.count++; // Anzahl Zeichen im Fifo +1 erhöhen } U1IER = UIER_ERBFI | UIER_ETBEI | UIER_ELSI; // IRQs einschalten LED1_OFF(); return (zeichen); } // Scheibt den Stringpuffer in den TX Fifo ein void UART1_Write() { uint8_t *ptr; // Zeiger auf String setzen ptr = (uint8_t*)gdisp_buf; do { uart1_put (*(ptr++)); } while (*ptr != 0); } //////////////////////////////////////////////////////////////////////////////////// /* Funktion: GDisplay_Init() Typ : normal Modul : gdriver.c -------------------------------------------------------------------------------- Beschreibung : Gibt ein Zeichen auf uart1 aus aufgerufene Funktionen : - Eingabeparameter : - Rückgabe : - veränderte Globals : - öffentlich/private : public letzte Änderung: 16.4.2009 */ ///////////////////////////////////////////////////////////////////////////////// void GDisplay_Init() { uint32_t i; uint8_t *ptr; // Den Busy Pin einstellen: PINMODE4 &= ~(0x03 << (2*BUSY_PIN)); // Pull Ups auf Busy Pin P2.2 einschalten PINSEL4 &= ~(0x3 << (2*BUSY_PIN)); // Busy Pin als GPIO definieren // Busy Pin P2.2 auf Eingang (=0) stellen (PINSEL4: Bits 4:5 = 00 FIO2DIRL &= (1 << BUSY_PIN); // UART einschalten uart1_init (38400); uart1_put (GDCMD_CLEAR_ALL); // Display löschen uart1_put (1); // Cursor auf 0,0 uart1_put (15); uart1_put (50); // Kontrast einstellen uart1_put (21); uart1_put (255); uart1_put (0); // Farben // Zeichenpuffer löschen ptr = (uint8_t*)GD_CharBuf; i = 0; while(i++ < sizeof(GD_CharBuf)) *(ptr++) = ' '; } //////////////////////////////////////////////////////////////////////////////////// /* Funktion: GDisplay_Print Typ : normal Modul : gdriver.c -------------------------------------------------------------------------------- Beschreibung : Schreibt eine Textzeile auf das Display an aktueller Cursorposition. Wird nach jeder sprintf aufgerufen aufgerufene Funktionen : uart1_put Eingabeparameter : spalte, zeile Rückgabe : - veränderte Globals : - öffentlich/private : public letzte Änderung: 16.4.2009 */ ///////////////////////////////////////////////////////////////////////////////// void GDisplay_Print() { uint8_t *ptr; // Zeiger auf String setzen ptr = gdisp_buf; do { while BUSY_GET_IN(); // Zeilenvorschub abfangen if (*ptr == '\n') { uart1_put (GDCMD_CURSOR_DOWN); uart1_put (GDCMD_CURSOR_LF); ptr++; } else uart1_put (*(ptr++)); } while (*ptr != 0); } void GDisplay_Print_Slow(uint32_t time) { uint8_t *ptr; // Zeiger auf String setzen ptr = gdisp_buf; do { while BUSY_GET_IN(); // Zeilenvorschub abfangen if (*ptr == '\n') { uart1_put (GDCMD_CURSOR_DOWN); uart1_put (GDCMD_CURSOR_LF); ptr++; } else{ uart1_put (*(ptr++)); delay_ms(1,time); } } while (*ptr != 0); } //////////////////////////////////////////////////////////////////////////////////// /* Funktion: void GD_Text_Refresh() Typ : normal Modul : gdriver.c -------------------------------------------------------------------------------- Beschreibung : Aktualisiert den Textbildschirm aufgerufene Funktionen : uart1_put Eingabeparameter : globaler Text Puffer Rückgabe : - veränderte Globals : - öffentlich/private : public letzte Änderung: 5.6.2009 */ ///////////////////////////////////////////////////////////////////////////////// char GD_Text_Refresh() { static uint16_t zeile_check[MAX_LINE]; // Checksumme für jede Zeile static uint8_t zeile_upd[MAX_LINE]; // 1= Update erforderlich, 0 = kein Update uint32_t x,y; uint16_t chk; uint8_t display_change = FALSE; // Prüfe für jede Zeile, ob ihr Inhalt verändert wurde for (y = 0;y < MAX_LINE;y++) { chk = 0; // Checksumme über Line bilden for (x = 0;x < MAX_LPOS;x++) chk += GD_CharBuf[y][x]; // Zeile braucht Update? if (chk != zeile_check[y]) { display_change = TRUE; // Der Displayinhalt wurde verändert zeile_upd[y] = TRUE; zeile_check[y] = chk; // Alte Checksumme erneuern } else zeile_upd[y] = FALSE; } // Wenn nichts verändert wurde -> raus if (!display_change) return 0; // Ersetze die Zeichen hinter der Endmarke der Strings durch Leerzeichen for (y = 0;y < MAX_LINE;y++) { if (zeile_upd[y] == TRUE) { x = 0; // Endmarke suchen while ((GD_CharBuf[y][x] != 0) && (x < MAX_LPOS)) x++; // und ab da auffüllen mit Leerzeichen if (x < MAX_LPOS) { for (;x < MAX_LPOS;x++) GD_CharBuf[y][x++]= ' '; } else // Zeile ist ganz voll GD_CharBuf[y][MAX_LPOS] = 0x00; } } // Trage die veränderten Zeilen ins Display ein. Es wird die komplette Zeile erneuert for (y = 0;y < MAX_LINE;y++) { if (zeile_upd[y] == TRUE) { // Cursor auf Spalte setzen GDisplay_Set_Cursor(0,y); // Veränderte Zeile an Display senden x = 0; while (GD_CharBuf[y][x] != 0) uart1_put (GD_CharBuf[y][x++]); } } return 1; } //////////////////////////////////////////////////////////////////////////////////// /* Funktion: void GD_PrintScroll() Typ : normal Modul : gdriver.c -------------------------------------------------------------------------------- Beschreibung : Schreibt eine Textzeile und scrollt wenn Ende des Disiplay erreicht wurde aufgerufene Funktionen : uart1_put Eingabeparameter : globaler Text Puffer Rückgabe : - veränderte Globals : - öffentlich/private : public letzte Änderung: 5.6.2009 */ ///////////////////////////////////////////////////////////////////////////////// void GD_PrintScroll() { } //////////////////////////////////////////////////////////////////////////////////// /* Funktion: void GD_ScrollBuffer() Typ : normal Modul : gdriver.c -------------------------------------------------------------------------------- Beschreibung : Scrollt den Texbuffer eine Zeile nach oben aufgerufene Funktionen : uart1_put Eingabeparameter : globaler Text Puffer Rückgabe : - veränderte Globals : - öffentlich/private : public letzte Änderung: 5.6.2009 */ ///////////////////////////////////////////////////////////////////////////////// void GD_ScrollBuffer() { uint32_t line,lpos; // Lines umkopieren for (line = 1;line < MAX_LINE;line++) { memcpy(&GD_CharBuf[line-1],&GD_CharBuf[line],MAX_LPOS); } // Letzte Line leer machen for (lpos = 0;lpos < MAX_LPOS;lpos++) GD_CharBuf[MAX_LINE-1][lpos] = ' '; GD_Text_Refresh(); } //////////////////////////////////////////////////////////////////////////////////// /* Funktion: GDisplay_Set_Cursor Typ : normal Modul : gdriver.c -------------------------------------------------------------------------------- Beschreibung : Setzt den Cursor auf eine Position aufgerufene Funktionen : uart1_put Eingabeparameter : spalte, zeile Rückgabe : - veränderte Globals : - öffentlich/private : public letzte Änderung: 16.4.2009 */ ///////////////////////////////////////////////////////////////////////////////// void GDisplay_Set_Cursor(uint8_t spalte, uint8_t zeile) { uart1_put (GDCMD_SETCURSOR); uart1_put (spalte); uart1_put (zeile); } //////////////////////////////////////////////////////////////////////////////////// /* Funktion: GDisplay_Reset_Cursor Typ : normal Modul : gdriver.c -------------------------------------------------------------------------------- Beschreibung : Setzt den Cursor auf 0,0 aufgerufene Funktionen : uart1_put Eingabeparameter : spalte, zeile Rückgabe : - veränderte Globals : - öffentlich/private : public letzte Änderung: 16.4.2009 */ ///////////////////////////////////////////////////////////////////////////////// void GDisplay_Reset_Cursor() { uart1_put (GDCMD_RESET_CURSOR); } void GDisplay_Clear() { uart1_put (GDCMD_CLEAR_ALL); }