Added ST7789 driver.

Signed-off-by: Yilin Sun <imi415@imi.moe>
This commit is contained in:
Yilin Sun 2023-10-29 01:22:24 +08:00
parent ebccc93243
commit d4b93f784e
Signed by: imi415
GPG Key ID: 17F01E106F9F5E0A
7 changed files with 289 additions and 4 deletions

View File

@ -1,8 +1,9 @@
BasedOnStyle: Google
IndentWidth: 4
AlignConsecutiveMacros: AcrossEmptyLines
AlignConsecutiveDeclarations: true
AlignConsecutiveAssignments: AcrossEmptyLinesAndComments
AlignConsecutiveMacros: Consecutive
AlignConsecutiveDeclarations: Consecutive
AlignConsecutiveAssignments: Consecutive
AllowShortFunctionsOnASingleLine: None
BreakBeforeBraces: Custom
BraceWrapping:
AfterEnum: false

View File

@ -5,8 +5,10 @@ project(epd-spi)
set(EPD_SOURCES
"src/epd_common.c"
"src/driver/oled_ssd1327.c"
"src/driver/lcd_st7789.c"
"src/panel/epd_wfh0420cz35.c"
"src/panel/epd_gdew042t2.c"
"src/panel/lcd_hp32030d.c"
"src/panel/lcd_jlx256128g_920.c"
"src/panel/lcd_zjy350c4001.c"
"src/panel/lcd_zjy096s0800.c"

View File

@ -0,0 +1,49 @@
#ifndef LCD_ST7789_H
#define LCD_ST7789_H
#include "epd-spi/epd_common.h"
typedef enum {
LCD_ST7789_DIR_0 = 0x08U,
LCD_ST7789_DIR_90 = 0x68U,
LCD_ST7789_DIR_180 = 0xC8U,
LCD_ST7789_DIR_270 = 0xA8U,
} lcd_st7789_direction_t;
typedef enum {
LCD_ST7789_RGB444 = 3,
LCD_ST7789_RGB565 = 5,
LCD_ST7789_RGB666 = 6,
LCD_ST7789_RGB888 = 7,
} lcd_st7789_pixel_format_t;
typedef struct {
uint8_t *init_struct;
uint32_t init_struct_length;
uint16_t ram_offset_x;
uint16_t ram_offset_y;
uint16_t size_x;
uint16_t size_y;
bool inversion;
bool bgr_filter;
} st7789_panel_config_t;
typedef struct {
void *user_data;
epd_cb_t cb;
const st7789_panel_config_t *panel_config;
lcd_st7789_direction_t direction;
lcd_st7789_pixel_format_t pixel_format;
} lcd_st7789_t;
epd_ret_t lcd_st7789_init(lcd_st7789_t *lcd, const st7789_panel_config_t *config);
epd_ret_t lcd_st7789_load(lcd_st7789_t *lcd, epd_coord_t *coord, const uint8_t *data);
epd_ret_t lcd_st7789_set_pixel_format(lcd_st7789_t *lcd, lcd_st7789_pixel_format_t format);
epd_ret_t lcd_st7789_set_direction(lcd_st7789_t *lcd, lcd_st7789_direction_t direction);
epd_ret_t lcd_st7789_set_inversion(lcd_st7789_t *lcd, bool invert);
#endif // LCD_ST7789_H

View File

@ -1,6 +1,7 @@
#ifndef EPD_COMMON_H
#define EPD_COMMON_H
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
@ -9,7 +10,7 @@ typedef enum { EPD_OK = 0, EPD_FAIL } epd_ret_t;
typedef struct {
epd_ret_t (*write_command_cb)(void *handle, uint8_t *command, uint32_t len);
epd_ret_t (*write_data_cb)(void *handle, uint8_t *data, uint32_t len);
epd_ret_t (*write_data_cb)(void *handle, const uint8_t *data, uint32_t len);
epd_ret_t (*reset_cb)(void *handle);
epd_ret_t (*poll_busy_cb)(void *handle);
epd_ret_t (*delay_cb)(void *handle, uint32_t msec);

View File

@ -0,0 +1,12 @@
//
// Created by imi415 on 23/10/21.
//
#ifndef LCD_HP32030D_H
#define LCD_HP32030D_H
#include "epd-spi/driver/lcd_st7789.h"
extern const st7789_panel_config_t lcd_hp32030d_panel_config;
#endif // LCD_HP32030D_H

189
src/driver/lcd_st7789.c Normal file
View File

@ -0,0 +1,189 @@
#include "driver/lcd_st7789.h"
#include "epd_private.h"
#define ST7789_CMD_SWRESET (0x01U)
#define ST7789_CMD_SLPIN (0x10U)
#define ST7789_CMD_SLPOUT (0x11U)
#define ST7789_CMD_INVOFF (0x20U)
#define ST7789_CMD_INVON (0x21U)
#define ST7789_CMD_CASET (0x2AU)
#define ST7789_CMD_RASET (0x2BU)
#define ST7789_CMD_RAMWR (0x2CU)
#define ST7789_CMD_MADCTL (0x36U)
#define ST7789_CMD_COLMOD (0x3AU)
static epd_ret_t lcd_st7789_reset(lcd_st7789_t *lcd);
static epd_ret_t lcd_st7789_sleep(lcd_st7789_t *lcd, bool sleep_mode);
static epd_ret_t lcd_st7789_panel_config(lcd_st7789_t *lcd, const st7789_panel_config_t *config);
static epd_ret_t lcd_st7789_set_window(lcd_st7789_t *lcd, epd_coord_t *coord);
epd_ret_t lcd_st7789_init(lcd_st7789_t *lcd, const st7789_panel_config_t *config) {
EPD_ERROR_CHECK(lcd_st7789_reset(lcd));
EPD_ERROR_CHECK(lcd->cb.delay_cb(lcd->user_data, 5));
EPD_ERROR_CHECK(lcd_st7789_sleep(lcd, false));
EPD_ERROR_CHECK(lcd->cb.delay_cb(lcd->user_data, 100));
EPD_ERROR_CHECK(lcd_st7789_panel_config(lcd, config));
EPD_ERROR_CHECK(lcd_st7789_set_pixel_format(lcd, LCD_ST7789_RGB565));
EPD_ERROR_CHECK(lcd_st7789_set_direction(lcd, LCD_ST7789_DIR_0));
EPD_ERROR_CHECK(lcd_st7789_set_inversion(lcd, false));
return EPD_OK;
}
epd_ret_t lcd_st7789_load(lcd_st7789_t *lcd, epd_coord_t *coord, const uint8_t *data) {
uint32_t pixel_count = (coord->y_end - coord->y_start + 1) * (coord->x_end - coord->x_start + 1);
uint32_t data_len = 0;
switch (lcd->pixel_format) {
case LCD_ST7789_RGB444:
data_len = pixel_count * 3 / 2;
break;
case LCD_ST7789_RGB565:
data_len = pixel_count * 2;
break;
case LCD_ST7789_RGB666:
case LCD_ST7789_RGB888:
data_len = pixel_count * 3;
break;
default:
data_len = pixel_count;
break;
}
// Set cursor
EPD_ERROR_CHECK(lcd_st7789_set_window(lcd, coord));
uint8_t command = ST7789_CMD_RAMWR; // Memory Write
EPD_ERROR_CHECK(lcd->cb.write_command_cb(lcd->user_data, &command, 0x01));
// Write pixel data
EPD_ERROR_CHECK(lcd->cb.write_data_cb(lcd->user_data, data, data_len));
return EPD_OK;
}
epd_ret_t lcd_st7789_set_pixel_format(lcd_st7789_t *lcd, lcd_st7789_pixel_format_t format) {
lcd->pixel_format = format;
uint8_t command[2] = {ST7789_CMD_COLMOD, format};
EPD_ERROR_CHECK(lcd->cb.write_command_cb(lcd->user_data, command, 0x02));
return EPD_OK;
}
epd_ret_t lcd_st7789_set_direction(lcd_st7789_t *lcd, lcd_st7789_direction_t direction) {
lcd->direction = direction;
uint8_t command[2] = {ST7789_CMD_MADCTL, direction};
if (!lcd->panel_config->bgr_filter) {
command[1] &= ~0x08U;
}
EPD_ERROR_CHECK(lcd->cb.write_command_cb(lcd->user_data, command, 0x02));
return EPD_OK;
}
epd_ret_t lcd_st7789_set_inversion(lcd_st7789_t *lcd, bool invert) {
uint8_t command[1];
if (lcd->panel_config->inversion) {
command[0] = invert ? ST7789_CMD_INVOFF : ST7789_CMD_INVON;
} else {
command[0] = invert ? ST7789_CMD_INVON : ST7789_CMD_INVOFF;
}
EPD_ERROR_CHECK(lcd->cb.write_command_cb(lcd->user_data, command, 0x01));
return EPD_OK;
}
static epd_ret_t lcd_st7789_reset(lcd_st7789_t *lcd) {
uint8_t cmd_buf[1] = {ST7789_CMD_SWRESET};
/* If hardware reset is implemented... */
if (lcd->cb.reset_cb) {
return lcd->cb.reset_cb(lcd->user_data);
} else {
return lcd->cb.write_command_cb(lcd->user_data, cmd_buf, 1U);
}
}
static epd_ret_t lcd_st7789_sleep(lcd_st7789_t *lcd, bool sleep_mode) {
uint8_t cmd_buf[1] = {ST7789_CMD_SLPOUT};
if (sleep_mode) {
cmd_buf[0] = ST7789_CMD_SLPIN;
}
return lcd->cb.write_command_cb(lcd->user_data, cmd_buf, 1U);
}
static epd_ret_t lcd_st7789_panel_config(lcd_st7789_t *lcd, const st7789_panel_config_t *config) {
uint32_t idx = 0U;
while (idx < config->init_struct_length) {
uint8_t *cmd_ptr = &config->init_struct[idx + 1];
uint8_t cmd_len = config->init_struct[idx] + 1;
EPD_ERROR_CHECK(lcd->cb.write_command_cb(lcd->user_data, cmd_ptr, cmd_len));
idx += config->init_struct[idx] + 2;
}
lcd->panel_config = config;
return EPD_OK;
}
static epd_ret_t lcd_st7789_set_window(lcd_st7789_t *lcd, epd_coord_t *coord) {
uint16_t real_x_start, real_x_end, real_y_start, real_y_end;
uint16_t x_offset, y_offset;
switch (lcd->direction) {
case LCD_ST7789_DIR_0:
x_offset = lcd->panel_config->ram_offset_x;
y_offset = lcd->panel_config->ram_offset_y;
break;
case LCD_ST7789_DIR_90:
x_offset = lcd->panel_config->ram_offset_y;
y_offset = lcd->panel_config->ram_offset_x;
break;
case LCD_ST7789_DIR_180:
x_offset = 240 - (lcd->panel_config->ram_offset_x + lcd->panel_config->size_x);
y_offset = 320 - (lcd->panel_config->ram_offset_y + lcd->panel_config->size_y);
break;
case LCD_ST7789_DIR_270:
x_offset = 320 - (lcd->panel_config->ram_offset_y + lcd->panel_config->size_y);
y_offset = 240 - (lcd->panel_config->ram_offset_x + lcd->panel_config->size_x);
break;
default:
x_offset = 0;
y_offset = 0;
}
real_x_start = coord->x_start + x_offset;
real_x_end = coord->x_end + x_offset;
real_y_start = coord->y_start + y_offset;
real_y_end = coord->y_end + y_offset;
uint8_t tx_buf[5] = {
ST7789_CMD_CASET, ((uint8_t)(real_x_start >> 0x08U) & 0xFFU),
(real_x_start & 0xFFU), ((uint8_t)(real_x_end >> 0x08U) & 0xFFU),
(real_x_end & 0xFFU),
};
EPD_ERROR_CHECK(lcd->cb.write_command_cb(lcd->user_data, tx_buf, 0x05));
tx_buf[0] = ST7789_CMD_RASET;
tx_buf[1] = ((uint8_t)(real_y_start >> 0x08U) & 0xFFU);
tx_buf[2] = (real_y_start & 0xFFU);
tx_buf[3] = ((uint8_t)(real_y_end >> 0x08U) & 0xFFU);
tx_buf[4] = (real_y_end & 0xFFU);
EPD_ERROR_CHECK(lcd->cb.write_command_cb(lcd->user_data, tx_buf, 0x05));
return EPD_OK;
}

31
src/panel/lcd_hp32030d.c Normal file
View File

@ -0,0 +1,31 @@
#include "panel/lcd_hp32030d.h"
static uint8_t panel_init_struct[] = {
0x05, 0xB2, 0x0C, 0x0C, 0x00, 0x33, 0x33, // PORCTRL(B2H)
0x02, 0xB0, 0x00, 0xE0, // RAMCTRL (B0H)
0x01, 0x36, 0x00, // MADCTL (36H)
0x01, 0x3A, 0x05, // COLMOD (3AH)
0x01, 0xB7, 0x56, // GCTRL (B7H)
0x01, 0xBB, 0x14, // VCOMS (BBH)
0x01, 0xC0, 0x2C, // LCMCTRL (C0H)
0x01, 0xC2, 0x01, // VDVVRHEN (C2H)
0x01, 0xC3, 0x0B, // VRHS (C3H)
0x01, 0xC4, 0x10, // VDVS (C4H)
0x01, 0xC6, 0x0F, // FRCTRL2 (C6H)
0x02, 0xD0, 0xA4, 0xA1, // PWCTRL1 (D0H)
0x01, 0xD5, 0xA1, // ??
0x0E, 0xE0, 0xD0, 0x08, 0x0A, 0x0D, 0x0B, 0x07, 0x21, 0x33, 0x39, 0x39, 0x16, 0x16, 0x1F, 0x3C, // PGC (E0H)
0x0E, 0xE1, 0xD0, 0x00, 0x03, 0x01, 0x00, 0x10, 0x21, 0x32, 0x38, 0x16, 0x14, 0x14, 0x20, 0x3D, // NGC (E1H)
0x00, 0x21, 0x00, 0x29, 0x00, 0x2C,
};
const st7789_panel_config_t lcd_hp32030d_panel_config = {
.init_struct = panel_init_struct,
.init_struct_length = sizeof(panel_init_struct),
.ram_offset_x = 0U,
.ram_offset_y = 0U,
.size_x = 240,
.size_y = 320,
.inversion = true,
.bgr_filter = false,
};