lvgl_esp32_drivers/lvgl_tft/st7789.c

261 lines
7.6 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* @file st7789.c
*
* Mostly taken from lbthomsen/esp-idf-littlevgl github.
*/
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "sdkconfig.h"
#include "esp_log.h"
#include "st7789.h"
#include "disp_spi.h"
#include "driver/gpio.h"
#include "esp_idf_version.h"
#if ESP_IDF_VERSION <= ESP_IDF_VERSION_VAL(5,0,0)
#include "rom/gpio.h"
#endif
/*********************
* DEFINES
*********************/
#define TAG "st7789"
/**********************
* TYPEDEFS
**********************/
/*The LCD needs a bunch of command/argument values to be initialized. They are stored in this struct. */
typedef struct {
uint8_t cmd;
uint8_t data[16];
uint8_t databytes; //No of data in data; bit 7 = delay after set; 0xFF = end of cmds.
} lcd_init_cmd_t;
/**********************
* STATIC PROTOTYPES
**********************/
static void st7789_set_orientation(uint8_t orientation);
static void st7789_send_color(void *data, size_t length);
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
void st7789_init(void)
{
lcd_init_cmd_t st7789_init_cmds[] = {
{0xCF, {0x00, 0x83, 0X30}, 3},
{0xED, {0x64, 0x03, 0X12, 0X81}, 4},
{ST7789_PWCTRL2, {0x85, 0x01, 0x79}, 3},
{0xCB, {0x39, 0x2C, 0x00, 0x34, 0x02}, 5},
{0xF7, {0x20}, 1},
{0xEA, {0x00, 0x00}, 2},
{ST7789_LCMCTRL, {0x26}, 1},
{ST7789_IDSET, {0x11}, 1},
{ST7789_VCMOFSET, {0x35, 0x3E}, 2},
{ST7789_CABCCTRL, {0xBE}, 1},
{ST7789_MADCTL, {0x00}, 1}, // Set to 0x28 if your display is flipped
{ST7789_COLMOD, {0x55}, 1},
#if ST7789_INVERT_COLORS == 1
{ST7789_INVON, {0}, 0}, // set inverted mode
#else
{ST7789_INVOFF, {0}, 0}, // set non-inverted mode
#endif
{ST7789_RGBCTRL, {0x00, 0x1B}, 2},
{0xF2, {0x08}, 1},
{ST7789_GAMSET, {0x01}, 1},
{ST7789_PVGAMCTRL, {0xD0, 0x00, 0x02, 0x07, 0x0A, 0x28, 0x32, 0x44, 0x42, 0x06, 0x0E, 0x12, 0x14, 0x17}, 14},
{ST7789_NVGAMCTRL, {0xD0, 0x00, 0x02, 0x07, 0x0A, 0x28, 0x31, 0x54, 0x47, 0x0E, 0x1C, 0x17, 0x1B, 0x1E}, 14},
{ST7789_CASET, {0x00, 0x00, 0x00, 0xEF}, 4},
{ST7789_RASET, {0x00, 0x00, 0x01, 0x3f}, 4},
{ST7789_RAMWR, {0}, 0},
{ST7789_GCTRL, {0x07}, 1},
{0xB6, {0x0A, 0x82, 0x27, 0x00}, 4},
{ST7789_SLPOUT, {0}, 0x80},
{ST7789_DISPON, {0}, 0x80},
{0, {0}, 0xff},
};
//Initialize non-SPI GPIOs
#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5,0,0)
gpio_pad_select_gpio(ST7789_DC);
#else
esp_rom_gpio_pad_select_gpio(ST7789_DC);
#endif
gpio_set_direction(ST7789_DC, GPIO_MODE_OUTPUT);
#if !defined(ST7789_SOFT_RST)
#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5,0,0)
gpio_pad_select_gpio(ST7789_RST);
#else
esp_rom_gpio_pad_select_gpio(ST7789_RST);
#endif
gpio_set_direction(ST7789_RST, GPIO_MODE_OUTPUT);
#endif
//Reset the display
#if !defined(ST7789_SOFT_RST)
gpio_set_level(ST7789_RST, 0);
vTaskDelay(100 / portTICK_PERIOD_MS);
gpio_set_level(ST7789_RST, 1);
vTaskDelay(100 / portTICK_PERIOD_MS);
#else
st7789_send_cmd(ST7789_SWRESET);
#endif
printf("ST7789 initialization.\n");
//Send all the commands
uint16_t cmd = 0;
while (st7789_init_cmds[cmd].databytes!=0xff) {
st7789_send_cmd(st7789_init_cmds[cmd].cmd);
st7789_send_data(st7789_init_cmds[cmd].data, st7789_init_cmds[cmd].databytes&0x1F);
if (st7789_init_cmds[cmd].databytes & 0x80) {
vTaskDelay(100 / portTICK_PERIOD_MS);
}
cmd++;
}
st7789_set_orientation(CONFIG_LV_DISPLAY_ORIENTATION);
}
/* The ST7789 display controller can drive up to 320*240 displays, when using a 240*240 or 240*135
* displays there's a gap of 80px or 40/52/53px respectively. 52px or 53x offset depends on display orientation.
* We need to edit the coordinates to take into account those gaps, this is not necessary in all orientations. */
void st7789_flush(lv_disp_drv_t * drv, const lv_area_t * area, lv_color_t * color_map)
{
uint8_t data[4] = {0};
uint16_t offsetx1 = area->x1;
uint16_t offsetx2 = area->x2;
uint16_t offsety1 = area->y1;
uint16_t offsety2 = area->y2;
#if (CONFIG_LV_TFT_DISPLAY_OFFSETS)
offsetx1 += CONFIG_LV_TFT_DISPLAY_X_OFFSET;
offsetx2 += CONFIG_LV_TFT_DISPLAY_X_OFFSET;
offsety1 += CONFIG_LV_TFT_DISPLAY_Y_OFFSET;
offsety2 += CONFIG_LV_TFT_DISPLAY_Y_OFFSET;
#elif (LV_HOR_RES_MAX == 240) && (LV_VER_RES_MAX == 240)
#if (CONFIG_LV_DISPLAY_ORIENTATION_PORTRAIT)
offsetx1 += 80;
offsetx2 += 80;
#elif (CONFIG_LV_DISPLAY_ORIENTATION_LANDSCAPE_INVERTED)
offsety1 += 80;
offsety2 += 80;
#endif
#elif (LV_HOR_RES_MAX == 240) && (LV_VER_RES_MAX == 135)
#if (CONFIG_LV_DISPLAY_ORIENTATION_PORTRAIT) || \
(CONFIG_LV_DISPLAY_ORIENTATION_PORTRAIT_INVERTED)
offsetx1 += 40;
offsetx2 += 40;
offsety1 += 53;
offsety2 += 53;
#endif
#elif (LV_HOR_RES_MAX == 135) && (LV_VER_RES_MAX == 240)
#if (CONFIG_LV_DISPLAY_ORIENTATION_LANDSCAPE) || \
(CONFIG_LV_DISPLAY_ORIENTATION_LANDSCAPE_INVERTED)
offsetx1 += 52;
offsetx2 += 52;
offsety1 += 40;
offsety2 += 40;
#endif
#elif (LV_HOR_RES_MAX == 320) && (LV_VER_RES_MAX == 170) // 1.9 inch 170×320 LCD, physically landscape
#if (CONFIG_LV_DISPLAY_ORIENTATION_PORTRAIT) || (CONFIG_LV_DISPLAY_ORIENTATION_PORTRAIT_INVERTED)
offsety1 += 35;
offsety2 += 35;
#endif
#elif (LV_HOR_RES_MAX == 170) && (LV_VER_RES_MAX == 320) // 1.9 inch 170×320 LCD, physically vertical
#if (CONFIG_LV_DISPLAY_ORIENTATION_LANDSCAPE) || (CONFIG_LV_DISPLAY_ORIENTATION_LANDSCAPE_INVERTED)
offsetx1 += 35;
offsetx2 += 35;
#endif
#endif
/*Column addresses*/
st7789_send_cmd(ST7789_CASET);
data[0] = (offsetx1 >> 8) & 0xFF;
data[1] = offsetx1 & 0xFF;
data[2] = (offsetx2 >> 8) & 0xFF;
data[3] = offsetx2 & 0xFF;
st7789_send_data(data, 4);
/*Page addresses*/
st7789_send_cmd(ST7789_RASET);
data[0] = (offsety1 >> 8) & 0xFF;
data[1] = offsety1 & 0xFF;
data[2] = (offsety2 >> 8) & 0xFF;
data[3] = offsety2 & 0xFF;
st7789_send_data(data, 4);
/*Memory write*/
st7789_send_cmd(ST7789_RAMWR);
size_t size = (size_t)lv_area_get_width(area) * (size_t)lv_area_get_height(area);
st7789_send_color((void*)color_map, size * 2);
}
/**********************
* STATIC FUNCTIONS
**********************/
void st7789_send_cmd(uint8_t cmd)
{
disp_wait_for_pending_transactions();
gpio_set_level(ST7789_DC, 0);
disp_spi_send_data(&cmd, 1);
}
void st7789_send_data(void * data, uint16_t length)
{
disp_wait_for_pending_transactions();
gpio_set_level(ST7789_DC, 1);
disp_spi_send_data(data, length);
}
static void st7789_send_color(void * data, size_t length)
{
disp_wait_for_pending_transactions();
gpio_set_level(ST7789_DC, 1);
disp_spi_send_colors(data, length);
}
static void st7789_set_orientation(uint8_t orientation)
{
// ESP_ASSERT(orientation < 4);
const char *orientation_str[] = {
"PORTRAIT", "PORTRAIT_INVERTED", "LANDSCAPE", "LANDSCAPE_INVERTED"
};
ESP_LOGI(TAG, "Display orientation: %s", orientation_str[orientation]);
uint8_t data[] =
{
#if CONFIG_LV_PREDEFINED_DISPLAY_TTGO
0x60, 0xA0, 0x00, 0xC0
#else
0xC0, 0x00, 0x60, 0xA0
#endif
};
ESP_LOGI(TAG, "0x36 command value: 0x%02X", data[orientation]);
st7789_send_cmd(ST7789_MADCTL);
st7789_send_data((void *) &data[orientation], 1);
}