/* * KDP ST7789 Panel driver * * Copyright (C) 2019 Kneron, Inc. All rights reserved. * */ #include "kdrv_gdma.h" #include "kdrv_display.h" #include "kdrv_lcm.h" #include "kdrv_pwm.h" #include "kl520_include.h" #include "kdev_status.h" osMutexId_t mutex_st7789 = NULL; osMutexId_t mutex_snapshot = NULL; #define TE_ENABLE #define PORTRAIT_DMA_ENABLE #define FRAME_RATE_60HZ 0 #define FRAME_RATE_39HZ 1 #define FRAME_RATE_CTRL FRAME_RATE_60HZ #define RAM_ENDIAN_MSB 0 #define RAM_ENDIAN_LSB 1 #define RAM_ENDIAN_TYPE RAM_ENDIAN_MSB /* This command is used to transfer data from MCU to frame memory. -When this command is accepted, the column register and the page register are reset to the start column/start page positions. -The start column/start page positions are different in accordance with MADCTL setting. -Sending any other command can stop frame write. */ #define PANEL_REG_RAMWR 0x2C //Memory write #define PANEL_REG_WRMEMC 0x3C //Write memory continue //#define ST7789_LANDSCAPE #define ST7789_PORTRAIT #ifdef ST7789_PORTRAIT //#define ST7789_PORTRAIT_PARTIAL //#define ZOOM_IN_RATIO 3/2 #endif #ifdef ST7789_LANDSCAPE #define ST7789_PANEL_WIDTH QVGA_LANDSCAPE_WIDTH #define ST7789_PANEL_HEIGHT QVGA_LANDSCAPE_HEIGHT #else #define ST7789_PANEL_WIDTH QVGA_PORTRAIT_WIDTH #define ST7789_PANEL_HEIGHT QVGA_PORTRAIT_HEIGHT #endif #define ST7789_PANEL_TOTAL_PIXEL ST7789_PANEL_WIDTH * ST7789_PANEL_HEIGHT #define OPEN_DOWN_SCALING #define BYTES_PER_PIXEL 2 #ifdef PORTRAIT_DMA_ENABLE #undef TE_ENABLE #undef FRAME_RATE_CTRL #undef RAM_ENDIAN_TYPE #define FRAME_RATE_CTRL FRAME_RATE_39HZ #define RAM_ENDIAN_TYPE RAM_ENDIAN_LSB #define TE_ENABLE #endif kdev_status_t kdev_panel_initialize(kdrv_display_t *display_drv) { if(display_drv == NULL) return KDEV_STATUS_ERROR; if(mutex_st7789 == NULL) mutex_st7789 = osMutexNew(NULL); if(mutex_snapshot == NULL) mutex_snapshot = osMutexNew(NULL); uint32_t base = display_drv->base; // u16 hor_no_in = display_drv->vi_params.input_xres; // u16 ver_no_in = display_drv->vi_params.input_yres; // u16 hor_no_out = ST7789_PANEL_WIDTH;//MZT_PANEL_WIDTH; // u16 ver_no_out = ST7789_PANEL_HEIGHT;//MZT_PANEL_HEIGHT; // DSG("[%s] hor_no_in=%u ver_no_in=%u hor_no_out=%u ver_no_out=%u", // __func__, hor_no_in, ver_no_in, hor_no_out, ver_no_out); kdrv_lcm_write_cmd(base, 0x11); //Exit Sleep //kdrv_delay_us(100); kdrv_pwmtimer_delay_ms(10); //-----------Display and color format setting-------------// // Column Address Set kdrv_lcm_write_cmd(base, 0x2A); // XS kdrv_lcm_write_data(base, 0x00); kdrv_lcm_write_data(base, 0x00); // XE #ifdef ST7789_LANDSCAPE kdrv_lcm_write_data(base, 0x01); kdrv_lcm_write_data(base, 0x3F); #else kdrv_lcm_write_data(base, 0x00); kdrv_lcm_write_data(base, 0xEF); #endif // Row Address Set kdrv_lcm_write_cmd(base, 0x2B); #ifdef ST7789_LANDSCAPE // YS kdrv_lcm_write_data(base, 0x00); kdrv_lcm_write_data(base, 0x00); // YE kdrv_lcm_write_data(base, 0x00); kdrv_lcm_write_data(base, 0xEF); #else #ifdef ST7789_PORTRAIT_PARTIAL // YS kdrv_lcm_write_data(base, 0x00); kdrv_lcm_write_data(base, 0x40); // YE kdrv_lcm_write_data(base, 0x01); kdrv_lcm_write_data(base, 0x00); #else // YS kdrv_lcm_write_data(base, 0x00); kdrv_lcm_write_data(base, 0x00); // YE kdrv_lcm_write_data(base, 0x01); kdrv_lcm_write_data(base, 0x3F); #endif #endif #ifdef ST7789_PORTRAIT_PARTIAL kdrv_lcm_write_cmd(base, 0x13); kdrv_lcm_write_data(base, 0x00); kdrv_lcm_write_cmd(base, 0x12); kdrv_lcm_write_data(base, 0xFF); kdrv_lcm_write_cmd(base, 0x30); kdrv_lcm_write_data(base, 0x00); kdrv_lcm_write_data(base, 0x40); kdrv_lcm_write_data(base, 0x01); kdrv_lcm_write_data(base, 0x00); #endif #ifdef TE_ENABLE kdrv_lcm_write_cmd(base, 0x35); // Enable Tearing effect kdrv_lcm_write_data(base, 0x00); #endif kdrv_lcm_write_cmd(base, 0x36); // Memory Access Control #ifdef ST7789_LANDSCAPE // xy_exchange / y_inverse //(Rotate positive 90 degrees) //MY = 1, MX = 0, MV = 1, ML = 0 kdrv_lcm_write_data(base, 0xA0); #else //MY = 1, MX = 1, MV = 0, ML = 0 //0820,Tei/Jeff { //ops->write_data(base, 0x40); //image from camera kdrv_lcm_write_data(base, 0x00); //image from flash } #endif // Interface Pixel Format kdrv_lcm_write_cmd(base, 0x3a);//DPI=101 16bit RGB kdrv_lcm_write_data(base, 0x55); //ops->write_data(base, 0x05); //-------------ST7789V Porch setting-----------// kdrv_lcm_write_cmd(base, 0xb2); kdrv_lcm_write_data(base, 0x0C); // Back porch (normal) kdrv_lcm_write_data(base, 0x0C); // Front porch (normal) kdrv_lcm_write_data(base, 0x00); // kdrv_lcm_write_data(base, 0X33); // Back porch (idle) + Front porch (idle) kdrv_lcm_write_data(base, 0X33); // Back porch (partial) + Front porch (partial) // Gate Control. 13.26, -10.43 kdrv_lcm_write_cmd(base, 0xb7); kdrv_lcm_write_data(base, 0x35);//(0x71); //Setting limitation: VCOMS+VCOMS offset+VDV=0.1V~1.675V. // VCOMS Setting. used for feed through voltage compensation // 1.175V kdrv_lcm_write_cmd(base, 0xBB); kdrv_lcm_write_data(base, 0x2b);//(0x25); // LCM Control ??? kdrv_lcm_write_cmd(base, 0xC0); kdrv_lcm_write_data(base, 0x2c); // VDV and VRH command enable kdrv_lcm_write_cmd(base, 0xC2); kdrv_lcm_write_data(base, 0x01); // VRH Set kdrv_lcm_write_cmd(base, 0xC3); kdrv_lcm_write_data(base, 0x11);//(0X14);// // VDVS Set kdrv_lcm_write_cmd(base, 0xC4); kdrv_lcm_write_data(base, 0x20); // 0 // Frame rate control in normal mode #if FRAME_RATE_CTRL == FRAME_RATE_60HZ kdrv_lcm_write_cmd(base, 0xC6); kdrv_lcm_write_data(base, 0x0F); #elif FRAME_RATE_CTRL == FRAME_RATE_39HZ kdrv_lcm_write_cmd(base, 0xC6); kdrv_lcm_write_data(base, 0x1F); #endif // Power Control 1 kdrv_lcm_write_cmd(base, 0xd0); kdrv_lcm_write_data(base, 0xa4); kdrv_lcm_write_data(base, 0xa1); // AVDD : 6.8V, AVCL : -4.6V, VDDS : 2.3 V //---------------ST7789V gamma setting-------------// { // Positive Voltage gamma control kdrv_lcm_write_cmd(base, 0xE0); kdrv_lcm_write_data(base, 0xd0); kdrv_lcm_write_data(base, 0x08); kdrv_lcm_write_data(base, 0x0e); kdrv_lcm_write_data(base, 0x0a); kdrv_lcm_write_data(base, 0x0a); kdrv_lcm_write_data(base, 0x06); kdrv_lcm_write_data(base, 0x38); kdrv_lcm_write_data(base, 0x44); kdrv_lcm_write_data(base, 0x50); kdrv_lcm_write_data(base, 0x29); kdrv_lcm_write_data(base, 0x15); kdrv_lcm_write_data(base, 0x16); kdrv_lcm_write_data(base, 0x33); kdrv_lcm_write_data(base, 0x36); } { // Negative Boltage gamma control kdrv_lcm_write_cmd(base, 0XE1); kdrv_lcm_write_data(base, 0xd0); kdrv_lcm_write_data(base, 0x07); kdrv_lcm_write_data(base, 0x0d); kdrv_lcm_write_data(base, 0x09); kdrv_lcm_write_data(base, 0x08); kdrv_lcm_write_data(base, 0x06); kdrv_lcm_write_data(base, 0x33); kdrv_lcm_write_data(base, 0x33); kdrv_lcm_write_data(base, 0x4d); kdrv_lcm_write_data(base, 0x28); kdrv_lcm_write_data(base, 0x16); kdrv_lcm_write_data(base, 0x15); kdrv_lcm_write_data(base, 0x33); kdrv_lcm_write_data(base, 0x35); } kdrv_lcm_write_cmd(base, 0x21); // Display Inversion On ?? // RAM Control #if RAM_ENDIAN_TYPE == RAM_ENDIAN_MSB kdrv_lcm_write_cmd(base, 0xB0); kdrv_lcm_write_data(base, 0x00); // Ram access from MCU interface kdrv_lcm_write_data(base, 0xd0); // Normal Endian (MSB first), 18 bit bus width #elif RAM_ENDIAN_TYPE == RAM_ENDIAN_LSB kdrv_lcm_write_cmd(base, 0xB0); kdrv_lcm_write_data(base, 0x00); // Ram access from MCU interface kdrv_lcm_write_data(base, 0xd8); // Normal Endian (MSB first), 18 bit bus width #endif kdrv_lcm_write_cmd(base, 0x29); //Display on //ops->write_cmd(base, 0x28); //Display off //_st7789_240x320_clear(display_drv, YELLOW);//WHITE); return KDEV_STATUS_OK; } kdev_status_t kdev_panel_clear(kdrv_display_t *display_drv, u32 color) { int i; if(display_drv == NULL) return KDEV_STATUS_ERROR; kdrv_lcm_write_cmd(display_drv->base, PANEL_REG_WRMEMC); for(i = 0; i < ST7789_PANEL_TOTAL_PIXEL; ++i) { kdrv_lcm_write_data(display_drv->base, (u8)((((color & 0xFF00) >>8 ) & 0xFF))); kdrv_lcm_write_data(display_drv->base, (u8)(color & 0x00FF)); } return KDEV_STATUS_OK; } uint16_t kdev_panel_read_display_id(kdrv_display_t *display_drv) { uint32_t base; uint16_t id = 0; if(display_drv == NULL) return 0xFFFF; base = display_drv->base; kdrv_lcm_write_cmd(base, 0x04); id = kdrv_lcm_read_data(base); //dummy read id = kdrv_lcm_read_data(base); id = ((kdrv_lcm_read_data(base) & 0xBF) << 8); id |= kdrv_lcm_read_data(base); return id; } kdev_status_t kdev_panel_refresh(kdrv_display_t* display_drv) { uint32_t base; uint32_t readAddr = kdrv_lcm_get_db_frame(); uint16_t lcm_w = display_drv->vi_params.input_xres; #ifdef ST7789_PORTRAIT_PARTIAL uint16_t lcm_h = 192;//ST7789_PANEL_HEIGHT; #else uint16_t lcm_h = display_drv->vi_params.input_yres; #endif if(display_drv == NULL) return KDEV_STATUS_ERROR; base = display_drv->base; #if 0//ndef ST7789_PORTRAIT_PARTIAL //home point : (0, 0) kdrv_display_write_cmd(base, 0x2A); kdrv_display_write_data(base, 0x00); kdrv_display_write_data(base, 0x00); kdrv_display_write_data(base, 0x00); kdrv_display_write_data(base, 0xEF); kdrv_display_write_cmd(base, 0x2B); kdrv_display_write_data(base, 0x00); kdrv_display_write_data(base, 0x00); kdrv_display_write_data(base, 0x01); kdrv_display_write_data(base, 0x3F); #endif osThreadId_t tid = osThreadGetId(); osPriority_t save_pri = osThreadGetPriority(tid); kdrv_lcm_write_cmd(base, PANEL_REG_RAMWR); //kdp520_gpio_setedgemode( 1 << GPIO_16, 0); //osThreadSetPriority(tid, save_pri+1); //TODO: (save_pri+1) is dangerous, below workaround is just to remove warning, // programmer must fix this. osThreadSetPriority(tid, (osPriority_t)((uint32_t)save_pri+1)); //kdp520_gpio_enableint( GPIO_16, GPIO_EDGE, false); //kdp520_wait_gpio_int(1<