383 lines
12 KiB
C
383 lines
12 KiB
C
/*
|
|
* 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<<GPIO_16);
|
|
//kdp520_gpio_disableint(GPIO_16);
|
|
|
|
static bool dma_configured = false;
|
|
static kdrv_gdma_handle_t dma_handle;
|
|
|
|
if(!dma_configured)
|
|
{
|
|
kdrv_gdma_acquire_handle(&dma_handle);
|
|
|
|
gdma_setting_t dma_setting;
|
|
dma_setting.dst_width = GDMA_TXFER_WIDTH_8_BITS;
|
|
dma_setting.src_width = GDMA_TXFER_WIDTH_32_BITS;
|
|
dma_setting.burst_size = GDMA_BURST_SIZE_32;
|
|
dma_setting.dst_addr_ctrl = GDMA_FIXED_ADDRESS;
|
|
dma_setting.src_addr_ctrl = GDMA_INCREMENT_ADDRESS;
|
|
dma_setting.dma_mode = GDMA_NORMAL_MODE;
|
|
dma_setting.dma_dst_req = 0;
|
|
dma_setting.dma_src_req = 0;
|
|
kdrv_gdma_configure_setting(dma_handle, &dma_setting);
|
|
|
|
dma_configured = true;
|
|
}
|
|
kdrv_gdma_transfer(dma_handle, (uint32_t)0xC340020c, (uint32_t)(readAddr), lcm_w*lcm_h*2);
|
|
osThreadSetPriority(tid, save_pri);
|
|
|
|
return KDEV_STATUS_OK;
|
|
}
|
|
|