209 lines
6.7 KiB
C
209 lines
6.7 KiB
C
#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_DISPOFF (0x28U)
|
|
#define ST7789_CMD_DISPON (0x29U)
|
|
#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));
|
|
|
|
if (lcd->cb.backlight_cb) {
|
|
EPD_ERROR_CHECK(lcd->cb.backlight_cb(lcd, 1));
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
epd_ret_t lcd_st7789_enable_display(lcd_st7789_t *lcd, bool on) {
|
|
uint8_t command[1];
|
|
|
|
if (on) {
|
|
command[0] = ST7789_CMD_DISPON;
|
|
} else {
|
|
command[0] = ST7789_CMD_DISPOFF;
|
|
}
|
|
|
|
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 = lcd->panel_config->ram_size_x - (lcd->panel_config->ram_offset_x + lcd->panel_config->size_x);
|
|
y_offset = lcd->panel_config->ram_size_y - (lcd->panel_config->ram_offset_y + lcd->panel_config->size_y);
|
|
break;
|
|
case LCD_ST7789_DIR_270:
|
|
x_offset = lcd->panel_config->ram_size_y - (lcd->panel_config->ram_offset_y + lcd->panel_config->size_y);
|
|
y_offset = lcd->panel_config->ram_size_x - (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;
|
|
} |