// LCD-Ansteuerung Low Level // Achtung!!! Controller ist der ILI9325, die Angabe im Datenblatt des Displays ist falsch!!!!! #include "LCD.h" #include "stm32f446xx.h" #include "stdlib.h" #include "cpu_init.h" /* LCD Ports * D0: PA9 * D1: PC7 * D2: PA10 * D3: PB3 * D4: PB5 * D5: PB4 * D6: PB10 * D7: PA8 * RST: PC1 (High aktiv) * CS: PB0 * RS: PA4 * WR: PA1 * RD: PA0 * * */ uint8_t LCD_getPortBits(void) { return (uint8_t)(((GPIOA->IDR & 0x100) >> 1) // D7 + ((GPIOA->IDR & 0x200) >> 9) // D0 + ((GPIOA->IDR & 0x400) >> 8) // D2 + ((GPIOB->IDR & 0x8)) // D3 + ((GPIOB->IDR & 0x10) << 1) // D5 + ((GPIOB->IDR & 0x20) >> 1) // D4 + ((GPIOB->IDR & 0x400) >> 4) // D6 + ((GPIOC->IDR & 0x80) >> 6)); // D1 } // Hilfsfunktion zum Setzen der Datenbits auf den Port void LCD_setPortBits(uint32_t data) { // Portbits PA8, PA9, PA10 löschen GPIOA->BSRR = 0x07000000; // PA8, 9, 10 entsprechend zu schreibendem Byte setzen (D0, D2, D7, RD high GPIOA->BSRR = ((data & 1)<< 9) + ((data & 4)<< 8) + ((data & 128)<< 1) + 1; // Portbits PB3, PB4, PB5, PB10 löschen GPIOB->BSRR = 0x04380000; // PB 3,4,5,10 entsprechend Daten setzen GPIOB->BSRR = ((data & 8)) + ((data & 16)<< 1) + ((data & 32)>> 1) + ((data & 64)<< 4); // Portbits PC7 löschen GPIOC->BSRR = 0x00800000; // PC7 entsprechend Daten setzen GPIOC->BSRR = ((data & 2) << 6); } // schaltet Datenbus auf Ausgang void LCD_enableBus(void) { //PA8,9,10 GPIOA->MODER = GPIOA->MODER | 0x00150000; // PB3,4,5,10 GPIOB->MODER = GPIOB->MODER | 0x00100540; // PC7 GPIOC->MODER = GPIOC->MODER | 0x00004000; } // schaltet Datenbus auf Eingang void LCD_disableBus(void) { //PA8,9,10 GPIOA->MODER = GPIOA->MODER & ~0x00150000; // PB3,4,5,10 GPIOB->MODER = GPIOB->MODER & ~0x00100540; // PC7 GPIOC->MODER = GPIOC->MODER & ~0x00004000; } // CS low oder high setzen void LCD_setCS(int Level) { if (Level == 0) GPIOB->BSRR = 0x10000; // CS low else GPIOB->BSRR = 1; // CS high } // Byte schreiben, wahlweise als Kommando (0) oder Daten (1) void LCD_writeByte(uint8_t data, int cmd_data) { if (cmd_data == 0) GPIOA->BSRR = 0x100000; // RS low LCD_setPortBits(data); LCD_enableBus(); GPIOA->BSRR = 0x20000; // WR low //GPIOA->BSRR = 2; // WR high GPIOA->BSRR = 0x12; // RS high LCD_disableBus(); } // Byte lesen uint8_t LCD_readByte(void) { volatile int i; GPIOA->BSRR = 0x10000; // RD low i = LCD_getPortBits(); GPIOA->BSRR = 1; // RD high return i; } /**************************************/ // Touch Screen lesen: // PB0(IN8): X (RS Low und D0 High), PA4(IN4): Y (CS High und D1 Low) // zuerst RS auf Low und D0 auf High, CS und D1 floatend, Kanal 4 von ADC2 samplen -> X // CS auf High und D1 auf Low, RS und D0 floatend, Kanal 8 samplen -> Y xy_t LCD_getIntTouch(void) { xy_t Result; // D0: PA9, D1: PC7, CS: PB0, RS: PA4 // zuerst D0 auf High, RS auf Low, CS und D1 floatend GPIOA->BSRR = 0x100200; // D0 auf High und RS auf Low GPIOA->MODER = GPIOA->MODER | 0x00040100; // D0 und RS als Ausgang GPIOB->MODER = GPIOB->MODER | 3; // CS als analoger Pin // D1 auf Low, danach floatend, um 'Touch' zu erkennen GPIOC->BSRR = 0x80; GPIOC->MODER = GPIOC->MODER | 0x4000; GPIOC->MODER = GPIOC->MODER & ~0x4000; // A/D-Wandlung Kanal 8 starten ADC2->CR2 = ADC2->CR2 | 0x40000000; // wartem, bis Wandlung fertig ist while ((ADC2->SR & 2) == 0); // Resultat lesen Result.y = ADC2->DR; // Umschalten auf Kanal 4 ADC2->SQR3 = 4; // CS High, D1 Low, D0 floatend, RS als Analogeingang GPIOA->MODER = GPIOA->MODER & ~0x40000; // D0 floatend GPIOC->MODER = GPIOC->MODER | 0x4000; // D1 als Ausgang GPIOC->BSRR = 0x800000; // D1 auf Low GPIOB->MODER = GPIOB->MODER & ~2; // CS als Ausgang GPIOB->BSRR = 1; // CS High GPIOA->MODER = GPIOA->MODER | 0x300; // PA4 analog // A/D-Wandlung Kanal 4 starten ADC2->CR2 = ADC2->CR2 | 0x40000000; // warten, bis Wandlung fertig ist while ((ADC2->SR & 2) == 0); // Resultat lesen Result.x = ADC2->DR; // Umschalten auf Kanal 8 ADC2->SQR3 = 8; // RS als Ausgang, D1 floatend GPIOA->MODER = GPIOA->MODER & ~0x200; GPIOC->MODER = GPIOC->MODER & ~0x4000; GPIOA->BSRR = 0x10; // RS High if (Result.y > 3600) { // kein 'Touch' Result.x = 32767; Result.y = 32767; } else { Result.x = 4095 - Result.x; Result.y = 4095 - Result.y; } return Result; } /**************************************************************/ // Portunabhängige Funktionen // falls keine Berührung, ist x und y auf 32767 xy_t LCD_getTouch(void) { xy_t t1, t2, t3; const int TOLERANZ = 20; const int XMAX = 3850; const int YMAX = 3450; const int XMIN = 600; const int YMIN = 300; const int XOFFSET = 34; const int YOFFSET = 29; LCD_setCS(1); do { t1 = LCD_getIntTouch(); t2 = LCD_getIntTouch(); t3 = LCD_getIntTouch(); } while((abs(t1.x-t2.x) > TOLERANZ) || (abs(t1.y - t2.y) > TOLERANZ) || (abs(t1.x-t3.x) > TOLERANZ) || (abs(t1.y - t3.y) > TOLERANZ)); if (t1.x != 32767) { t1.x = t1.x * 320 / (XMAX - XMIN) - XOFFSET; t1.y = t1.y * 240 / (YMAX - YMIN) - YOFFSET; } LCD_setCS(0); return t1; } void LCD_Write_COM_DATA(uint8_t cmd, uint16_t data) { LCD_writeByte(0, 0); LCD_writeByte(cmd, 0); // Kommandobyte LCD_writeByte(data >> 8, 1); LCD_writeByte(data & 255, 1); } // Schreiben eines Pixels (16 Bit Farbe) void LCD_writePixel(uint16_t color) { LCD_writeByte(color >> 8, 1); LCD_writeByte(color & 255, 1); } // Adresspointer setzen void LCD_setXY(uint16_t x, uint16_t y) { LCD_Write_COM_DATA(0x20, y); LCD_Write_COM_DATA(0x21, x); LCD_writeByte(0, 0); LCD_writeByte(0x22, 0); } // Adressrange für Rechteck definieren // Adresspointer wird auf obere linke Ecke gesetzt void LCD_setRect(uint16_t x1, uint16_t x2, uint16_t y1, uint16_t y2) { uint16_t temp; if (x2 < x1) { temp = x2; x2 = x1; x1 = temp; } if (y2 < y1) { temp = y2; y2 = y1; y1 = temp; } LCD_Write_COM_DATA(0x50, y1); LCD_Write_COM_DATA(0x51, y2); LCD_Write_COM_DATA(0x52, x1); LCD_Write_COM_DATA(0x53, x2); LCD_Write_COM_DATA(0x20, y1); LCD_Write_COM_DATA(0x21, x1); LCD_writeByte(0, 0); LCD_writeByte(0x22, 0); } // Konvertierung RGB nach 16bit-Farbe uint16_t LCD_getColor(uint8_t R, uint8_t G, uint8_t B) { // Farben auf 5 (6) Bit begrenzen R = R >> 3; B = B >> 3; G = G >> 2; return (uint16_t)(B) + ((uint16_t)(G) << 5) + ((uint16_t)(R) << 11); } void LCD_init(void) { // Pullup D1 für Touch Screen GPIOC->PUPDR = 0x4000; LCD_setCS(1); // Hardware-Reset GPIOC->BSRR = 0x20000; delay(100); GPIOC->BSRR = 0x2; // Reset aufheben delay(500); LCD_setCS(0); // Initialisierung 16 Bit Farben (dadurch nur 2 Bytes/Pixel, ergibt schnelleren Update) LCD_Write_COM_DATA(0xE5, 0x78F0); // set SRAM internal timing LCD_Write_COM_DATA(0x01, 0x0200); // set Driver Output Control (Bit 10 prüfen, zusammen mit r60) LCD_Write_COM_DATA(0x02, 0x0300); // set 1 line inversion LCD_Write_COM_DATA(0x03, 0x3038); // set GRAM write direction, BGR = 1, TRI = 0, AM = 1, DFM = 1, ORG = 0, ID=11 LCD_Write_COM_DATA(0x04, 0x0000); // Resize register LCD_Write_COM_DATA(0x08, 0x0207); // set the back porch and front porch LCD_Write_COM_DATA(0x09, 0x0000); // set non-display area refresh cycle ISC[3:0] LCD_Write_COM_DATA(0x0A, 0x0000); // FMARK function LCD_Write_COM_DATA(0x0C, 0x0000); // RGB interface setting LCD_Write_COM_DATA(0x0D, 0x0000); // Frame marker Position LCD_Write_COM_DATA(0x0F, 0x0000); // RGB interface polarity //*************Power On sequence ****************// LCD_Write_COM_DATA(0x10, 0x0000); // SAP, BT[3:0], AP, DSTB, SLP, STB LCD_Write_COM_DATA(0x11, 0x0007); // DC1[2:0], DC0[2:0], VC[2:0] LCD_Write_COM_DATA(0x12, 0x0000); // VREG1OUT voltage LCD_Write_COM_DATA(0x13, 0x0000); // VDV[4:0] for VCOM amplitude LCD_Write_COM_DATA(0x07, 0x0001); delay(200); // Dis-charge capacitor power voltage LCD_Write_COM_DATA(0x10, 0x1690); // SAP, BT[3:0], AP, DSTB, SLP, STB LCD_Write_COM_DATA(0x11, 0x0227); // Set DC1[2:0], DC0[2:0], VC[2:0] delay(50); // Delay 50ms LCD_Write_COM_DATA(0x12, 0x000D); // 0012 delay(50); // Delay 50ms LCD_Write_COM_DATA(0x13, 0x1200); // VDV[4:0] for VCOM amplitude LCD_Write_COM_DATA(0x29, 0x000A); // 04 VCM[5:0] for VCOMH LCD_Write_COM_DATA(0x2B, 0x000D); // Set Frame Rate delay(50); // Delay 50ms LCD_Write_COM_DATA(0x20,0); // GRAM horizontal Address LCD_Write_COM_DATA(0x21,0); // GRAM Vertical Address // ----------- Adjust the Gamma Curve ----------// LCD_Write_COM_DATA(0x30, 0x0000); LCD_Write_COM_DATA(0x31, 0x0404); LCD_Write_COM_DATA(0x32, 0x0003); LCD_Write_COM_DATA(0x35, 0x0405); LCD_Write_COM_DATA(0x36, 0x0808); LCD_Write_COM_DATA(0x37, 0x0407); LCD_Write_COM_DATA(0x38, 0x0303); LCD_Write_COM_DATA(0x39, 0x0707); LCD_Write_COM_DATA(0x3C, 0x0504); LCD_Write_COM_DATA(0x3D, 0x0808); //------------------ Set GRAM area ---------------// LCD_Write_COM_DATA(0x50,0); // Horizontal GRAM Start Address LCD_Write_COM_DATA(0x51,240-1); // Horizontal GRAM End Address LCD_Write_COM_DATA(0x52,0); // Vertical GRAM Start Address LCD_Write_COM_DATA(0x53,320-1); // Vertical GRAM Start Address LCD_Write_COM_DATA(0x60, 0xa700); // Gate Scan Line LCD_Write_COM_DATA(0x61, 0x0001); // NDL,VLE, REV LCD_Write_COM_DATA(0x6A, 0x0000); // set scrolling line //-------------- Partial Display Control ---------// LCD_Write_COM_DATA(0x80, 0x0000); LCD_Write_COM_DATA(0x81, 0x0000); LCD_Write_COM_DATA(0x82, 0x0000); LCD_Write_COM_DATA(0x83, 0x0000); LCD_Write_COM_DATA(0x84, 0x0000); LCD_Write_COM_DATA(0x85, 0x0000); //-------------- Panel Control -------------------// LCD_Write_COM_DATA(0x07, 0x0133); // 262K color and display ON // Display löschen LCD_Write_COM_DATA(0x20,0); // GRAM Vertical Address LCD_Write_COM_DATA(0x21,0); // GRAM horizontal Address LCD_writeByte(0, 0); LCD_writeByte(0x22, 0); }