#include "py32f030.h" void LCD_GPIO_config(void); void delay_loop(int iDelay); void LCD_setup(void); void LCD_init(void); void LCD_transfer_test(void); void do_display_init_and_test(void) { LCD_GPIO_config(); delay_loop(500); LCD_setup(); LCD_init(); delay_loop(5000); LCD_transfer_test(); // forever for(;;) { } } // Display related pins // PB4: LCD Reset (0 for Reset) #define LCD_PIN_BIT_RESET (4) #define LCD_PIN_RESET (1UL << LCD_PIN_BIT_RESET) #define LCD_PORT_RESET GPIOB // PB3: LCD Clock #define LCD_PIN_BIT_CLOCK (3) #define LCD_PIN_CLOCK (1UL << LCD_PIN_BIT_CLOCK) #define LCD_PORT_CLOCK GPIOB // PB5: LCD Data #define LCD_PIN_BIT_DATA (5) #define LCD_PIN_DATA (1UL << LCD_PIN_BIT_DATA) #define LCD_PORT_DATA GPIOB // PA8: LCD Select (0 for Select) #define LCD_PIN_BIT_SELECT (8) #define LCD_PIN_SELECT (1UL << LCD_PIN_BIT_SELECT) #define LCD_PORT_SELECT GPIOA // PA12: LCD Commmand or Data (0 for Command) #define LCD_PIN_BIT_CMD_DATA (12) #define LCD_PIN_CMD_DATA (1UL << LCD_PIN_BIT_CMD_DATA) #define LCD_PORT_CMD_DATA GPIOA // PA11: LCD Backlight (1 for On) #define LCD_PIN_BIT_BACKLIGHT (11) #define LCD_PIN_BACKLIGHT (1UL << LCD_PIN_BIT_BACKLIGHT) #define LCD_PORT_BACKLIGHT GPIOA // Set GPIO Pin State void LCD_Reset(int iReset) { if(iReset) LCD_PORT_RESET->BRR = (LCD_PIN_RESET); // set to 0 (reset) else LCD_PORT_RESET->BSRR = (LCD_PIN_RESET); // set to 1 } void LCD_Clock(int iClockLevel) { if(iClockLevel) LCD_PORT_CLOCK->BSRR = (LCD_PIN_CLOCK); // set to 1 else LCD_PORT_CLOCK->BRR = (LCD_PIN_CLOCK); // set to 0 } void LCD_Select(int iSelect) { if(iSelect) LCD_PORT_SELECT->BRR = (LCD_PIN_SELECT); // set to 0 (select) else LCD_PORT_SELECT->BSRR = (LCD_PIN_SELECT); // set to 1 } void LCD_Command(int iCommand) { if(iCommand) LCD_PORT_CMD_DATA->BRR = (LCD_PIN_CMD_DATA); // set to 0 (command) else LCD_PORT_CMD_DATA->BSRR = (LCD_PIN_CMD_DATA); // set to 1 } void LCD_set_Data(int iDataLevel) { if(iDataLevel) LCD_PORT_DATA->BSRR = (LCD_PIN_DATA); // set to 1 else LCD_PORT_DATA->BRR = (LCD_PIN_DATA); // set to 0 } void LCD_Backlight(int iPowerOn) { if(iPowerOn) LCD_PORT_BACKLIGHT->BSRR = (LCD_PIN_BACKLIGHT); // set to 1 (on) else LCD_PORT_BACKLIGHT->BRR = (LCD_PIN_BACKLIGHT); // set to 0 } // all Pins are Output void LCD_GPIO_config(void) { // Data // MODERy[1:0] - 01: Output mode LCD_PORT_DATA->MODER |= (1UL << (LCD_PIN_BIT_DATA * 2 + 0)); LCD_PORT_DATA->MODER &= ~(1UL << (LCD_PIN_BIT_DATA * 2 + 1)); // Reset // MODERy[1:0] - 01: Output mode LCD_PORT_RESET->MODER |= (1UL << (LCD_PIN_BIT_RESET * 2 + 0)); LCD_PORT_RESET->MODER &= ~(1UL << (LCD_PIN_BIT_RESET * 2 + 1)); // Clock // MODERy[1:0] - 01: Output mode LCD_PORT_CLOCK->MODER |= (1UL << (LCD_PIN_BIT_CLOCK * 2 + 0)); LCD_PORT_CLOCK->MODER &= ~(1UL << (LCD_PIN_BIT_CLOCK * 2 + 1)); // Select // MODERy[1:0] - 01: Output mode LCD_PORT_SELECT->MODER |= (1UL << (LCD_PIN_BIT_SELECT * 2 + 0)); LCD_PORT_SELECT->MODER &= ~(1UL << (LCD_PIN_BIT_SELECT * 2 + 1)); // Command/Data // MODERy[1:0] - 01: Output mode LCD_PORT_CMD_DATA->MODER |= (1UL << (LCD_PIN_BIT_CMD_DATA * 2 + 0)); LCD_PORT_CMD_DATA->MODER &= ~(1UL << (LCD_PIN_BIT_CMD_DATA * 2 + 1)); // Backlight // MODERy[1:0] - 01: Output mode LCD_PORT_BACKLIGHT->MODER |= (1UL << (LCD_PIN_BIT_BACKLIGHT * 2 + 0)); LCD_PORT_BACKLIGHT->MODER &= ~(1UL << (LCD_PIN_BIT_BACKLIGHT * 2 + 1)); } // TODO: adjust as necessary void delay_loop(int iDelay) { int i; for(i = 0; i < iDelay * 2; i++) { asm(" nop "); } } // SPI Bit-Banging void LCD_shift_out_byte(uint8_t u8_byte) { int i; for(i = 0; i < 8; i++) { if(u8_byte & (1 << (7 - i))) // MSB first LCD_set_Data(1); else LCD_set_Data(0); LCD_Clock(0); delay_loop(1); LCD_Clock(1); delay_loop(1); } } // just reset the Display Controller void LCD_setup(void) { LCD_Backlight(0); // Backlight off LCD_Select(1); // 1 -> select LCD_Reset(0); // 0 -> no Reset delay_loop(500); LCD_Reset(1); // 1 -> Reset delay_loop(5000); LCD_Reset(0); // 0 -> no Reset delay_loop(12000); } // send command byte void LCD_send_CMD_byte(uint8_t u8_byte) { LCD_Select(1); // 1 -> select LCD_Command(1); // 1 -> command LCD_shift_out_byte(u8_byte); LCD_Select(0); // 0 -> not selected } // send data byte void LCD_send_DATA_byte(uint8_t u8_byte) { LCD_Select(1); // 1 -> select LCD_Command(0); // 0 -> data LCD_shift_out_byte(u8_byte); LCD_Select(0); // 0 -> not selected } // The firmware decides from "Read display identification information (04h)" // which variant should be used. On my device it is the second variant // There are no obvious visible differences when using the first variant // instead. void LCD_init(void) { #if 0 // Variant 1 LCD_send_CMD_byte(0xFF); LCD_send_DATA_byte(0xA5); delay_loop(1000); LCD_send_CMD_byte(0xFF); LCD_send_DATA_byte(0xA5); delay_loop(1000); LCD_send_CMD_byte(0xFF); LCD_send_DATA_byte(0xA5); ///////////////// LCD_send_CMD_byte(0x3E); LCD_send_DATA_byte(0x08); // COLMOD: Pixel Format Set (3Ah) LCD_send_CMD_byte(0x3A); LCD_send_DATA_byte(0x65); LCD_send_CMD_byte(0x82); LCD_send_DATA_byte(0x00); LCD_send_CMD_byte(0x98); LCD_send_DATA_byte(0x00); LCD_send_CMD_byte(0x63); LCD_send_DATA_byte(0x0F); LCD_send_CMD_byte(0x64); LCD_send_DATA_byte(0x0F); LCD_send_CMD_byte(0xB4); LCD_send_DATA_byte(0x34); LCD_send_CMD_byte(0xB5); LCD_send_DATA_byte(0x30); LCD_send_CMD_byte(0x83); LCD_send_DATA_byte(0x13); LCD_send_CMD_byte(0x86); LCD_send_DATA_byte(0x04); LCD_send_CMD_byte(0x87); LCD_send_DATA_byte(0x16); LCD_send_CMD_byte(0x88); LCD_send_DATA_byte(0x28); LCD_send_CMD_byte(0x89); LCD_send_DATA_byte(0x2F); LCD_send_CMD_byte(0x93); LCD_send_DATA_byte(0x63); LCD_send_CMD_byte(0x96); LCD_send_DATA_byte(0x81); LCD_send_CMD_byte(0xC3); LCD_send_DATA_byte(0x11); LCD_send_CMD_byte(0xE6); LCD_send_DATA_byte(0x00); LCD_send_CMD_byte(0x99); LCD_send_DATA_byte(0x01); LCD_send_CMD_byte(0x44); LCD_send_DATA_byte(0x00); ///////////////// LCD_send_CMD_byte(0x70); LCD_send_DATA_byte(0x07); LCD_send_CMD_byte(0x71); LCD_send_DATA_byte(0x19); LCD_send_CMD_byte(0x72); LCD_send_DATA_byte(0x1A); LCD_send_CMD_byte(0x73); LCD_send_DATA_byte(0x13); LCD_send_CMD_byte(0x74); LCD_send_DATA_byte(0x19); LCD_send_CMD_byte(0x75); LCD_send_DATA_byte(0x1D); LCD_send_CMD_byte(0x76); LCD_send_DATA_byte(0x47); LCD_send_CMD_byte(0x77); LCD_send_DATA_byte(0x0A); LCD_send_CMD_byte(0x78); LCD_send_DATA_byte(0x07); LCD_send_CMD_byte(0x79); LCD_send_DATA_byte(0x47); LCD_send_CMD_byte(0x7A); LCD_send_DATA_byte(0x05); LCD_send_CMD_byte(0x7B); LCD_send_DATA_byte(0x09); LCD_send_CMD_byte(0x7C); LCD_send_DATA_byte(0x0D); LCD_send_CMD_byte(0x7D); LCD_send_DATA_byte(0x0C); LCD_send_CMD_byte(0x7E); LCD_send_DATA_byte(0x0C); LCD_send_CMD_byte(0x7F); LCD_send_DATA_byte(0x08); ///////////////// LCD_send_CMD_byte(0xA0); LCD_send_DATA_byte(0x0B); LCD_send_CMD_byte(0xA1); LCD_send_DATA_byte(0x36); LCD_send_CMD_byte(0xA2); LCD_send_DATA_byte(0x09); LCD_send_CMD_byte(0xA3); LCD_send_DATA_byte(0x0D); LCD_send_CMD_byte(0xA4); LCD_send_DATA_byte(0x08); LCD_send_CMD_byte(0xA5); LCD_send_DATA_byte(0x23); LCD_send_CMD_byte(0xA6); LCD_send_DATA_byte(0x3B); LCD_send_CMD_byte(0xA7); LCD_send_DATA_byte(0x04); LCD_send_CMD_byte(0xA8); LCD_send_DATA_byte(0x07); LCD_send_CMD_byte(0xA9); LCD_send_DATA_byte(0x38); LCD_send_CMD_byte(0xAA); LCD_send_DATA_byte(0x0A); LCD_send_CMD_byte(0xAB); LCD_send_DATA_byte(0x12); LCD_send_CMD_byte(0xAC); LCD_send_DATA_byte(0x0C); LCD_send_CMD_byte(0xAD); LCD_send_DATA_byte(0x07); LCD_send_CMD_byte(0xAE); LCD_send_DATA_byte(0x2F); LCD_send_CMD_byte(0xAF); LCD_send_DATA_byte(0x07); ///////////////// LCD_send_CMD_byte(0xFF); LCD_send_DATA_byte(0x00); LCD_send_CMD_byte(0x36); LCD_send_DATA_byte(0x40); LCD_send_CMD_byte(0x11); #else // Variant 2 LCD_send_CMD_byte(0xFF); LCD_send_DATA_byte(0xA5); LCD_send_CMD_byte(0x3E); LCD_send_DATA_byte(0x08); // COLMOD: Pixel Format Set (3Ah) LCD_send_CMD_byte(0x3A); LCD_send_DATA_byte(0x65); LCD_send_CMD_byte(0x82); LCD_send_DATA_byte(0x00); LCD_send_CMD_byte(0x98); LCD_send_DATA_byte(0x00); LCD_send_CMD_byte(0x63); LCD_send_DATA_byte(0x0F); LCD_send_CMD_byte(0x64); LCD_send_DATA_byte(0x0F); LCD_send_CMD_byte(0xB4); LCD_send_DATA_byte(0x34); LCD_send_CMD_byte(0xB5); LCD_send_DATA_byte(0x30); LCD_send_CMD_byte(0x83); LCD_send_DATA_byte(0x13); LCD_send_CMD_byte(0x86); LCD_send_DATA_byte(0x04); LCD_send_CMD_byte(0x87); LCD_send_DATA_byte(0x12); LCD_send_CMD_byte(0x88); LCD_send_DATA_byte(0x09); LCD_send_CMD_byte(0x89); LCD_send_DATA_byte(0x2F); LCD_send_CMD_byte(0x93); LCD_send_DATA_byte(0x63); LCD_send_CMD_byte(0x96); LCD_send_DATA_byte(0x81); LCD_send_CMD_byte(0xC3); LCD_send_DATA_byte(0x11); LCD_send_CMD_byte(0xE6); LCD_send_DATA_byte(0x00); LCD_send_CMD_byte(0x99); LCD_send_DATA_byte(0x01); LCD_send_CMD_byte(0x44); LCD_send_DATA_byte(0x00); ///////////////// LCD_send_CMD_byte(0x70); LCD_send_DATA_byte(0x07); LCD_send_CMD_byte(0x71); LCD_send_DATA_byte(0x1B); LCD_send_CMD_byte(0x72); LCD_send_DATA_byte(0x08); LCD_send_CMD_byte(0x73); LCD_send_DATA_byte(0x0F); LCD_send_CMD_byte(0x74); LCD_send_DATA_byte(0x16); LCD_send_CMD_byte(0x75); LCD_send_DATA_byte(0x1A); LCD_send_CMD_byte(0x76); LCD_send_DATA_byte(0x3C); LCD_send_CMD_byte(0x77); LCD_send_DATA_byte(0x0A); LCD_send_CMD_byte(0x78); LCD_send_DATA_byte(0x05); LCD_send_CMD_byte(0x79); LCD_send_DATA_byte(0x3A); LCD_send_CMD_byte(0x7A); LCD_send_DATA_byte(0x06); LCD_send_CMD_byte(0x7B); LCD_send_DATA_byte(0x0B); LCD_send_CMD_byte(0x7C); LCD_send_DATA_byte(0x12); LCD_send_CMD_byte(0x7D); LCD_send_DATA_byte(0x0B); LCD_send_CMD_byte(0x7E); LCD_send_DATA_byte(0x0A); LCD_send_CMD_byte(0x7F); LCD_send_DATA_byte(0x08); ///////////////// LCD_send_CMD_byte(0xA0); LCD_send_DATA_byte(0x0B); LCD_send_CMD_byte(0xA1); LCD_send_DATA_byte(0x36); LCD_send_CMD_byte(0xA2); LCD_send_DATA_byte(0x0B); LCD_send_CMD_byte(0xA3); LCD_send_DATA_byte(0x0C); LCD_send_CMD_byte(0xA4); LCD_send_DATA_byte(0x08); LCD_send_CMD_byte(0xA5); LCD_send_DATA_byte(0x22); LCD_send_CMD_byte(0xA6); LCD_send_DATA_byte(0x43); LCD_send_CMD_byte(0xA7); LCD_send_DATA_byte(0x04); LCD_send_CMD_byte(0xA8); LCD_send_DATA_byte(0x05); LCD_send_CMD_byte(0xA9); LCD_send_DATA_byte(0x3F); LCD_send_CMD_byte(0xAA); LCD_send_DATA_byte(0x0A); LCD_send_CMD_byte(0xAB); LCD_send_DATA_byte(0x11); LCD_send_CMD_byte(0xAC); LCD_send_DATA_byte(0x0D); LCD_send_CMD_byte(0xAD); LCD_send_DATA_byte(0x06); LCD_send_CMD_byte(0xAE); LCD_send_DATA_byte(0x3B); LCD_send_CMD_byte(0xAF); LCD_send_DATA_byte(0x07); ///////////////// LCD_send_CMD_byte(0xFF); LCD_send_DATA_byte(0x00); LCD_send_CMD_byte(0x36); LCD_send_DATA_byte(0x40); LCD_send_CMD_byte(0x11); #endif } // some RGB565 colors #define LCD_RGB565_BLACK 0x0000 #define LCD_RGB565_WHITE 0xFFFF #define LCD_RGB565_RED 0xF800 #define LCD_RGB565_GREEN 0x07E0 #define LCD_RGB565_BLUE 0x001F // send one RGB565 pixel to display void LCD_send_RGB565(uint16_t u16_rgb565) { LCD_send_DATA_byte((uint8_t)(u16_rgb565 >> 8)); LCD_send_DATA_byte((uint8_t)u16_rgb565 & 0xFF); } // Display dimension #define LCD_WIDTH 128 #define LCD_HEIGHT 160 // just a simple test to fill the display with some data void LCD_transfer_test(void) { uint8_t u8_col_start, u8_col_end; uint8_t u8_row_start, u8_row_end; // complete display area u8_col_start = 0; u8_col_end = LCD_WIDTH - 1; u8_row_start = 0; u8_row_end = LCD_HEIGHT - 1; LCD_Backlight(1); // Backlight on // Display ON (29h) LCD_send_CMD_byte(0x29); // Memory Access Control(36h) LCD_send_CMD_byte(0x36); LCD_send_DATA_byte(0x00); // Column Address Set (2Ah) LCD_send_CMD_byte(0x2A); LCD_send_DATA_byte(0x00); // Start high LCD_send_DATA_byte(u8_col_start); // Start low LCD_send_DATA_byte(0x00); // End high LCD_send_DATA_byte(u8_col_end); // End low // Row Address Set (2Bh) LCD_send_CMD_byte(0x2B); LCD_send_DATA_byte(0x00); // Start high LCD_send_DATA_byte(u8_row_start); // Start low LCD_send_DATA_byte(0x00); // End high LCD_send_DATA_byte(u8_row_end); // End low // Memory Write (2Ch) LCD_send_CMD_byte(0x2C); // send the pixels int row, col; for(row = u8_row_start; row <= u8_row_end; row++) { uint16_t color; // for 8 color bars int which_color = (row - u8_row_start) / ((u8_row_end + 1 - u8_row_start) / 8); if(which_color == 0) color = LCD_RGB565_WHITE; else if(which_color == 1) color = LCD_RGB565_RED; else if(which_color == 2) color = LCD_RGB565_GREEN; else if(which_color == 3) color = LCD_RGB565_BLUE; else if(which_color == 4) color = LCD_RGB565_BLACK; else if(which_color == 5) color = LCD_RGB565_RED | LCD_RGB565_GREEN; else if(which_color == 6) color = LCD_RGB565_RED | LCD_RGB565_BLUE; else color = LCD_RGB565_BLUE | LCD_RGB565_GREEN; for(col = u8_col_start; col <= u8_col_end; col++) { LCD_send_RGB565(color); } } }