KL520_SDK_2.2/platform/dev/panel/kdev_st7789_240x320.c
2025-12-17 15:55:25 +08:00

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;
}