除了显示驱动,其余全部测试通过

This commit is contained in:
guo
2026-08-30 14:13:24 +08:00
commit c0ace98dff
146 changed files with 9476 additions and 0 deletions
+473
View File
@@ -0,0 +1,473 @@
#include "st7789v2.h"
#include "app_config.h"
#include "asm/gpio.h"
#include "device/device.h"
#include "system/init.h"
#include "app_log.h"
#define LCD_SPI_NAME "spi2"
#define LCD_RES_PIN IO_PORTA_01
#define LCD_CS_PIN IO_PORTA_02
#define LCD_DC_PIN IO_PORTA_05
#define LCD_BL_PIN IO_PORTA_07
/* PA6 是 TE 引脚,但当前版本暂未启用 TE 同步 */
#define LCD_WIDTH 240
#define LCD_HEIGHT 320
#define LCD_PIXEL_BYTES 3
#define LCD_LINE_BYTES (LCD_WIDTH * LCD_PIXEL_BYTES)
#define LCD_CMD_SWRESET 0x01
#define LCD_CMD_SLPIN 0x10
#define LCD_CMD_SLPOUT 0x11
#define LCD_CMD_INVON 0x21
#define LCD_CMD_DISPOFF 0x28
#define LCD_CMD_DISPON 0x29
#define LCD_CMD_CASET 0x2A
#define LCD_CMD_RASET 0x2B
#define LCD_CMD_RAMWR 0x2C
static void *lcd_spi_hdl;
static u8 lcd_line_buf[LCD_LINE_BYTES];
static OS_MUTEX lcd_mutex;
struct lcd_init_entry {
u8 cmd;
u8 len;
u8 data[14];
};
/*
* B7、BB、C0、C3、C4、E0、E1 与具体玻璃面板有关。
* 这里保留原工程参数,量产前必须与模组厂初始化表核对。
*
* D6/A1 未列入公开 ST7789V2 命令表,因此不放入该序列。
*/
static const struct lcd_init_entry lcd_init_seq[] = {
{0x36, 1, {0x00}},
{0x3A, 1, {0x06}}, /* RGB666 */
{0xB2, 5, {0x0C, 0x0C, 0x00, 0x33, 0x33}},
{0xB7, 1, {0x46}},
{0xBB, 1, {0x1B}},
{0xC0, 1, {0x2C}},
{0xC2, 1, {0x01}},
{0xC3, 1, {0x0F}},
{0xC4, 1, {0x20}},
{0xC6, 1, {0x0F}},
{0xD0, 2, {0xA4, 0xA1}},
{0xE0, 14, {
0xD0, 0x06, 0x0B, 0x09, 0x08, 0x30, 0x30,
0x5B, 0x4B, 0x18, 0x14, 0x14, 0x2B, 0x31
}},
{0xE1, 14, {
0xD0, 0x05, 0x0A, 0x0A, 0x07, 0x28, 0x32,
0x2C, 0x49, 0x18, 0x13, 0x13, 0x2C, 0x33
}},
/*
* Display inversion:面板行列驱动反相。
* 它不是简单的软件颜色取反。
*/
{LCD_CMD_INVON, 0, {0x00}},
};
static int st7789v2_mutex_init(void)
{
return os_mutex_create(&lcd_mutex);
}
early_initcall(st7789v2_mutex_init);
static int lcd_lock(void)
{
if (!os_mutex_valid(&lcd_mutex)) {
return -EIO;
}
return os_mutex_pend(&lcd_mutex, 0);
}
static void lcd_unlock(void)
{
os_mutex_post(&lcd_mutex);
}
static void lcd_delay_ms(u32 ms)
{
u32 ticks;
ticks = (ms * OS_TICKS_PER_SEC + 999U) / 1000U;
if (ticks == 0) {
ticks = 1;
}
os_time_dly(ticks);
}
static void lcd_gpio_output(u32 pin, int value)
{
gpio_direction_output(pin, value);
}
static void lcd_cs(int value)
{
lcd_gpio_output(LCD_CS_PIN, value);
}
static void lcd_dc(int value)
{
lcd_gpio_output(LCD_DC_PIN, value);
}
static void lcd_reset(int value)
{
lcd_gpio_output(LCD_RES_PIN, value);
}
static void lcd_backlight_on(void)
{
lcd_gpio_output(LCD_BL_PIN, 1);
}
static void lcd_backlight_off(void)
{
lcd_gpio_output(LCD_BL_PIN, 0);
}
static int lcd_spi_write_locked(const void *buf, u32 len)
{
int ret;
if (!lcd_spi_hdl) {
return -ENODEV;
}
if (len == 0) {
return 0;
}
if (!buf) {
return -EINVAL;
}
/*
* 本 SDK 的 SPI dev_write() 使用 0 表示成功,
* 非 0 表示失败。
*/
ret = dev_write(lcd_spi_hdl, (void *)buf, len);
return ret;
}
static int lcd_write_cmd_raw_locked(u8 cmd)
{
lcd_dc(0);
return lcd_spi_write_locked(&cmd, 1);
}
static int lcd_write_data_raw_locked(const void *data, u32 len)
{
lcd_dc(1);
return lcd_spi_write_locked(data, len);
}
/*
* 一个完整命令事务:
* CS 低 -> 命令 -> 可选参数 -> CS 高
*/
static int lcd_send_command_locked(u8 cmd, const u8 *data, u32 len)
{
int ret;
lcd_cs(0);
ret = lcd_write_cmd_raw_locked(cmd);
if (ret == 0 && len != 0) {
ret = lcd_write_data_raw_locked(data, len);
}
lcd_cs(1);
if (ret != 0) {
APP_LOG("st7789v2: command 0x%02x failed, ret=%d\n",
cmd, ret);
}
return ret;
}
static void lcd_hardware_reset_locked(void)
{
lcd_cs(1);
lcd_dc(1);
lcd_reset(1);
lcd_delay_ms(10);
lcd_reset(0);
lcd_delay_ms(20);
lcd_reset(1);
lcd_delay_ms(120);
}
static int lcd_controller_init_locked(void)
{
int ret;
u32 i;
lcd_hardware_reset_locked();
ret = lcd_send_command_locked(LCD_CMD_SLPOUT, NULL, 0);
if (ret != 0) {
return ret;
}
lcd_delay_ms(120);
for (i = 0;
i < sizeof(lcd_init_seq) / sizeof(lcd_init_seq[0]);
i++) {
ret = lcd_send_command_locked(
lcd_init_seq[i].cmd,
lcd_init_seq[i].data,
lcd_init_seq[i].len);
if (ret != 0) {
return ret;
}
}
ret = lcd_send_command_locked(LCD_CMD_DISPON, NULL, 0);
if (ret != 0) {
return ret;
}
lcd_delay_ms(20);
return 0;
}
/*
* 调用本函数前 CS 必须已经拉低。
*/
static int lcd_set_window_raw_locked(u16 x1, u16 y1, u16 x2, u16 y2)
{
int ret;
u8 data[4];
data[0] = x1 >> 8;
data[1] = x1 & 0xff;
data[2] = x2 >> 8;
data[3] = x2 & 0xff;
ret = lcd_write_cmd_raw_locked(LCD_CMD_CASET);
if (ret != 0) {
return ret;
}
ret = lcd_write_data_raw_locked(data, sizeof(data));
if (ret != 0) {
return ret;
}
data[0] = y1 >> 8;
data[1] = y1 & 0xff;
data[2] = y2 >> 8;
data[3] = y2 & 0xff;
ret = lcd_write_cmd_raw_locked(LCD_CMD_RASET);
if (ret != 0) {
return ret;
}
ret = lcd_write_data_raw_locked(data, sizeof(data));
if (ret != 0) {
return ret;
}
return lcd_write_cmd_raw_locked(LCD_CMD_RAMWR);
}
static int lcd_fill_rgb_locked(u8 red, u8 green, u8 blue)
{
int ret;
u32 x;
u32 y;
if (!lcd_spi_hdl) {
return -ENODEV;
}
/*
* COLMOD=0x06 时为 RGB666。
* 每个颜色分量只有高 6 bit 有效。
*/
red &= 0xfc;
green &= 0xfc;
blue &= 0xfc;
for (x = 0; x < LCD_WIDTH; x++) {
lcd_line_buf[x * 3 + 0] = red;
lcd_line_buf[x * 3 + 1] = green;
lcd_line_buf[x * 3 + 2] = blue;
}
/*
* 窗口设置和所有像素属于同一个 SPI 事务。
* 任意错误发生时,也必须恢复 CS 高电平。
*/
lcd_cs(0);
ret = lcd_set_window_raw_locked(
0,
0,
LCD_WIDTH - 1,
LCD_HEIGHT - 1);
if (ret == 0) {
lcd_dc(1);
for (y = 0; y < LCD_HEIGHT; y++) {
ret = lcd_spi_write_locked(
lcd_line_buf,
sizeof(lcd_line_buf));
if (ret != 0) {
break;
}
}
}
lcd_cs(1);
return ret;
}
int st7789v2_open(void)
{
int ret;
ret = lcd_lock();
if (ret != 0) {
return ret;
}
if (lcd_spi_hdl) {
lcd_unlock();
return 0;
}
lcd_backlight_off();
lcd_cs(1);
lcd_dc(1);
lcd_reset(1);
lcd_spi_hdl = dev_open(LCD_SPI_NAME, NULL);
if (!lcd_spi_hdl) {
APP_LOG("st7789v2: dev_open(%s) failed\n",
LCD_SPI_NAME);
lcd_unlock();
return -ENODEV;
}
ret = lcd_controller_init_locked();
if (ret != 0) {
goto open_failed;
}
/*
* 背光打开前先清成黑色,避免显示未初始化显存。
* 1 MHz 下该操作约需要 1.84 秒。
*/
ret = lcd_fill_rgb_locked(0, 0, 0);
if (ret != 0) {
goto open_failed;
}
lcd_backlight_on();
lcd_unlock();
APP_LOG("st7789v2: open success\n");
return 0;
open_failed:
lcd_backlight_off();
lcd_cs(1);
dev_close(lcd_spi_hdl);
lcd_spi_hdl = NULL;
lcd_unlock();
APP_LOG("st7789v2: initialization failed, ret=%d\n",
ret);
return ret;
}
int st7789v2_close(void)
{
int ret;
int tmp;
ret = lcd_lock();
if (ret != 0) {
return ret;
}
lcd_backlight_off();
if (!lcd_spi_hdl) {
lcd_cs(1);
lcd_unlock();
return 0;
}
ret = lcd_send_command_locked(LCD_CMD_DISPOFF, NULL, 0);
lcd_delay_ms(20);
tmp = lcd_send_command_locked(LCD_CMD_SLPIN, NULL, 0);
if (ret == 0 && tmp != 0) {
ret = tmp;
}
/*
* 使用与 SDK 官方 SleepIn 类似的保守等待时间。
*/
lcd_delay_ms(120);
lcd_cs(1);
tmp = dev_close(lcd_spi_hdl);
lcd_spi_hdl = NULL;
if (ret == 0 && tmp != 0) {
ret = tmp;
}
lcd_unlock();
return ret;
}
int st7789v2_fill_rgb(u8 red, u8 green, u8 blue)
{
int ret;
ret = lcd_lock();
if (ret != 0) {
return ret;
}
ret = lcd_fill_rgb_locked(red, green, blue);
lcd_unlock();
if (ret != 0) {
APP_LOG("st7789v2: fill failed, ret=%d\n",
ret);
}
return ret;
}