Skip to content

Instantly share code, notes, and snippets.

@fallenartist
Created January 28, 2025 11:51
Show Gist options
  • Save fallenartist/22d1d01e125afb02ae4ebdcdf02d1f80 to your computer and use it in GitHub Desktop.
Save fallenartist/22d1d01e125afb02ae4ebdcdf02d1f80 to your computer and use it in GitHub Desktop.
Waveshare ESP32-S3 Touch LCD 2.1 Example
#include "Display_ST7701.h"
spi_device_handle_t SPI_handle = NULL;
esp_lcd_panel_handle_t panel_handle = NULL;
void ST7701_WriteCommand(uint8_t cmd)
{
spi_transaction_t spi_tran = {
.cmd = 0,
.addr = cmd,
.length = 0,
.rxlength = 0,
};
spi_device_transmit(SPI_handle, &spi_tran);
}
void ST7701_WriteData(uint8_t data)
{
spi_transaction_t spi_tran = {
.cmd = 1,
.addr = data,
.length = 0,
.rxlength = 0,
};
spi_device_transmit(SPI_handle, &spi_tran);
}
void ST7701_CS_EN(){
Set_EXIO(EXIO_PIN3,Low);
vTaskDelay(pdMS_TO_TICKS(10));
}
void ST7701_CS_Dis(){
Set_EXIO(EXIO_PIN3,High);
vTaskDelay(pdMS_TO_TICKS(10));
}
void ST7701_Reset(){
Set_EXIO(EXIO_PIN1,Low);
vTaskDelay(pdMS_TO_TICKS(10));
Set_EXIO(EXIO_PIN1,High);
vTaskDelay(pdMS_TO_TICKS(50));
}
void ST7701_Init()
{
spi_bus_config_t buscfg = {
.mosi_io_num = LCD_MOSI_PIN,
.miso_io_num = -1,
.sclk_io_num = LCD_CLK_PIN,
.quadwp_io_num = -1,
.quadhd_io_num = -1,
.max_transfer_sz = 64, // ESP32 S3 max size is 64Kbytes
};
spi_bus_initialize(SPI2_HOST, &buscfg, SPI_DMA_CH_AUTO);
spi_device_interface_config_t devcfg = {
.command_bits = 1,
.address_bits = 8,
.mode = SPI_MODE0,
.clock_speed_hz = 40000000,
.spics_io_num = -1,
.queue_size = 1, // Not using queues
};
spi_bus_add_device(SPI2_HOST, &devcfg, &SPI_handle);
ST7701_CS_EN();
ST7701_WriteCommand(0xFF);
ST7701_WriteData(0x77);
ST7701_WriteData(0x01);
ST7701_WriteData(0x00);
ST7701_WriteData(0x00);
ST7701_WriteData(0x10);
ST7701_WriteCommand(0xC0);
ST7701_WriteData(0x3B);//Scan line
ST7701_WriteData(0x00);
ST7701_WriteCommand(0xC1);
ST7701_WriteData(0x0B); //VBP
ST7701_WriteData(0x02);
ST7701_WriteCommand(0xC2);
ST7701_WriteData(0x07);
ST7701_WriteData(0x02);
ST7701_WriteCommand(0xCC);
ST7701_WriteData(0x10);
ST7701_WriteCommand(0xCD);//RGB format
ST7701_WriteData(0x08);
ST7701_WriteCommand(0xB0); // IPS
ST7701_WriteData(0x00); // 255
ST7701_WriteData(0x11); // 251
ST7701_WriteData(0x16); // 247 down
ST7701_WriteData(0x0e); // 239
ST7701_WriteData(0x11); // 231
ST7701_WriteData(0x06); // 203
ST7701_WriteData(0x05); // 175
ST7701_WriteData(0x09); // 147
ST7701_WriteData(0x08); // 108
ST7701_WriteData(0x21); // 80
ST7701_WriteData(0x06); // 52
ST7701_WriteData(0x13); // 24
ST7701_WriteData(0x10); // 16
ST7701_WriteData(0x29); // 8 down
ST7701_WriteData(0x31); // 4
ST7701_WriteData(0x18); // 0
ST7701_WriteCommand(0xB1);// IPS
ST7701_WriteData(0x00);// 255
ST7701_WriteData(0x11);// 251
ST7701_WriteData(0x16);// 247 down
ST7701_WriteData(0x0e);// 239
ST7701_WriteData(0x11);// 231
ST7701_WriteData(0x07);// 203
ST7701_WriteData(0x05);// 175
ST7701_WriteData(0x09);// 147
ST7701_WriteData(0x09);// 108
ST7701_WriteData(0x21);// 80
ST7701_WriteData(0x05);// 52
ST7701_WriteData(0x13);// 24
ST7701_WriteData(0x11);// 16
ST7701_WriteData(0x2a);// 8 down
ST7701_WriteData(0x31);// 4
ST7701_WriteData(0x18);// 0
ST7701_WriteCommand(0xFF);
ST7701_WriteData(0x77);
ST7701_WriteData(0x01);
ST7701_WriteData(0x00);
ST7701_WriteData(0x00);
ST7701_WriteData(0x11);
ST7701_WriteCommand(0xB0); //VOP 3.5375+ *x 0.0125
ST7701_WriteData(0x6d); //5D
ST7701_WriteCommand(0xB1); //VCOM amplitude setting
ST7701_WriteData(0x37); //
ST7701_WriteCommand(0xB2); //VGH Voltage setting
ST7701_WriteData(0x81); //12V
ST7701_WriteCommand(0xB3);
ST7701_WriteData(0x80);
ST7701_WriteCommand(0xB5); //VGL Voltage setting
ST7701_WriteData(0x43); //-8.3V
ST7701_WriteCommand(0xB7);
ST7701_WriteData(0x85);
ST7701_WriteCommand(0xB8);
ST7701_WriteData(0x20);
ST7701_WriteCommand(0xC1);
ST7701_WriteData(0x78);
ST7701_WriteCommand(0xC2);
ST7701_WriteData(0x78);
ST7701_WriteCommand(0xD0);
ST7701_WriteData(0x88);
ST7701_WriteCommand(0xE0);
ST7701_WriteData(0x00);
ST7701_WriteData(0x00);
ST7701_WriteData(0x02);
ST7701_WriteCommand(0xE1);
ST7701_WriteData(0x03);
ST7701_WriteData(0xA0);
ST7701_WriteData(0x00);
ST7701_WriteData(0x00);
ST7701_WriteData(0x04);
ST7701_WriteData(0xA0);
ST7701_WriteData(0x00);
ST7701_WriteData(0x00);
ST7701_WriteData(0x00);
ST7701_WriteData(0x20);
ST7701_WriteData(0x20);
ST7701_WriteCommand(0xE2);
ST7701_WriteData(0x00);
ST7701_WriteData(0x00);
ST7701_WriteData(0x00);
ST7701_WriteData(0x00);
ST7701_WriteData(0x00);
ST7701_WriteData(0x00);
ST7701_WriteData(0x00);
ST7701_WriteData(0x00);
ST7701_WriteData(0x00);
ST7701_WriteData(0x00);
ST7701_WriteData(0x00);
ST7701_WriteData(0x00);
ST7701_WriteData(0x00);
ST7701_WriteCommand(0xE3);
ST7701_WriteData(0x00);
ST7701_WriteData(0x00);
ST7701_WriteData(0x11);
ST7701_WriteData(0x00);
ST7701_WriteCommand(0xE4);
ST7701_WriteData(0x22);
ST7701_WriteData(0x00);
ST7701_WriteCommand(0xE5);
ST7701_WriteData(0x05);
ST7701_WriteData(0xEC);
ST7701_WriteData(0xA0);
ST7701_WriteData(0xA0);
ST7701_WriteData(0x07);
ST7701_WriteData(0xEE);
ST7701_WriteData(0xA0);
ST7701_WriteData(0xA0);
ST7701_WriteData(0x00);
ST7701_WriteData(0x00);
ST7701_WriteData(0x00);
ST7701_WriteData(0x00);
ST7701_WriteData(0x00);
ST7701_WriteData(0x00);
ST7701_WriteData(0x00);
ST7701_WriteData(0x00);
ST7701_WriteCommand(0xE6);
ST7701_WriteData(0x00);
ST7701_WriteData(0x00);
ST7701_WriteData(0x11);
ST7701_WriteData(0x00);
ST7701_WriteCommand(0xE7);
ST7701_WriteData(0x22);
ST7701_WriteData(0x00);
ST7701_WriteCommand(0xE8);
ST7701_WriteData(0x06);
ST7701_WriteData(0xED);
ST7701_WriteData(0xA0);
ST7701_WriteData(0xA0);
ST7701_WriteData(0x08);
ST7701_WriteData(0xEF);
ST7701_WriteData(0xA0);
ST7701_WriteData(0xA0);
ST7701_WriteData(0x00);
ST7701_WriteData(0x00);
ST7701_WriteData(0x00);
ST7701_WriteData(0x00);
ST7701_WriteData(0x00);
ST7701_WriteData(0x00);
ST7701_WriteData(0x00);
ST7701_WriteData(0x00);
ST7701_WriteCommand(0xEB);
ST7701_WriteData(0x00);
ST7701_WriteData(0x00);
ST7701_WriteData(0x40);
ST7701_WriteData(0x40);
ST7701_WriteData(0x00);
ST7701_WriteData(0x00);
ST7701_WriteData(0x00);
ST7701_WriteCommand(0xED);
ST7701_WriteData(0xFF);
ST7701_WriteData(0xFF);
ST7701_WriteData(0xFF);
ST7701_WriteData(0xBA);
ST7701_WriteData(0x0A);
ST7701_WriteData(0xBF);
ST7701_WriteData(0x45);
ST7701_WriteData(0xFF);
ST7701_WriteData(0xFF);
ST7701_WriteData(0x54);
ST7701_WriteData(0xFB);
ST7701_WriteData(0xA0);
ST7701_WriteData(0xAB);
ST7701_WriteData(0xFF);
ST7701_WriteData(0xFF);
ST7701_WriteData(0xFF);
ST7701_WriteCommand(0xEF);
ST7701_WriteData(0x10);
ST7701_WriteData(0x0D);
ST7701_WriteData(0x04);
ST7701_WriteData(0x08);
ST7701_WriteData(0x3F);
ST7701_WriteData(0x1F);
ST7701_WriteCommand(0xFF);
ST7701_WriteData(0x77);
ST7701_WriteData(0x01);
ST7701_WriteData(0x00);
ST7701_WriteData(0x00);
ST7701_WriteData(0x13);
ST7701_WriteCommand(0xEF);
ST7701_WriteData(0x08);
ST7701_WriteCommand(0xFF);
ST7701_WriteData(0x77);
ST7701_WriteData(0x01);
ST7701_WriteData(0x00);
ST7701_WriteData(0x00);
ST7701_WriteData(0x00);
ST7701_WriteCommand(0x36);
ST7701_WriteData(0x00);
ST7701_WriteCommand(0x3A);
ST7701_WriteData(0x66);
ST7701_WriteCommand(0x11);
vTaskDelay(pdMS_TO_TICKS(480));
ST7701_WriteCommand(0x20); //
vTaskDelay(pdMS_TO_TICKS(120));
ST7701_WriteCommand(0x29);
ST7701_CS_Dis();
// RGB
esp_lcd_rgb_panel_config_t rgb_config = {
.clk_src = LCD_CLK_SRC_DEFAULT,
.timings = {
.pclk_hz = ESP_PANEL_LCD_RGB_TIMING_FREQ_HZ,
.h_res = ESP_PANEL_LCD_HEIGHT,
.v_res = ESP_PANEL_LCD_WIDTH,
.hsync_pulse_width = ESP_PANEL_LCD_RGB_TIMING_HPW,
.hsync_back_porch = ESP_PANEL_LCD_RGB_TIMING_HBP,
.hsync_front_porch = ESP_PANEL_LCD_RGB_TIMING_HFP,
.vsync_pulse_width = ESP_PANEL_LCD_RGB_TIMING_VPW,
.vsync_back_porch = ESP_PANEL_LCD_RGB_TIMING_VBP,
.vsync_front_porch = ESP_PANEL_LCD_RGB_TIMING_VFP,
.flags = {
.hsync_idle_low = 0, /*!< The hsync signal is low in IDLE state */
.vsync_idle_low = 0, /*!< The vsync signal is low in IDLE state */
.de_idle_high = 0, /*!< The de signal is high in IDLE state */
.pclk_active_neg = false,
.pclk_idle_high = 0, /*!< The PCLK stays at high level in IDLE phase */
},
},
.data_width = ESP_PANEL_LCD_RGB_DATA_WIDTH,
.bits_per_pixel = ESP_PANEL_LCD_RGB_PIXEL_BITS,
.num_fbs = ESP_PANEL_LCD_RGB_FRAME_BUF_NUM,
.bounce_buffer_size_px = 10 * ESP_PANEL_LCD_HEIGHT,
.psram_trans_align = 64,
.hsync_gpio_num = ESP_PANEL_LCD_PIN_NUM_RGB_HSYNC,
.vsync_gpio_num = ESP_PANEL_LCD_PIN_NUM_RGB_VSYNC,
.de_gpio_num = ESP_PANEL_LCD_PIN_NUM_RGB_DE,
.pclk_gpio_num = ESP_PANEL_LCD_PIN_NUM_RGB_PCLK,
.disp_gpio_num = ESP_PANEL_LCD_PIN_NUM_RGB_DISP,
.data_gpio_nums = {
ESP_PANEL_LCD_PIN_NUM_RGB_DATA0,
ESP_PANEL_LCD_PIN_NUM_RGB_DATA1,
ESP_PANEL_LCD_PIN_NUM_RGB_DATA2,
ESP_PANEL_LCD_PIN_NUM_RGB_DATA3,
ESP_PANEL_LCD_PIN_NUM_RGB_DATA4,
ESP_PANEL_LCD_PIN_NUM_RGB_DATA5,
ESP_PANEL_LCD_PIN_NUM_RGB_DATA6,
ESP_PANEL_LCD_PIN_NUM_RGB_DATA7,
ESP_PANEL_LCD_PIN_NUM_RGB_DATA8,
ESP_PANEL_LCD_PIN_NUM_RGB_DATA9,
ESP_PANEL_LCD_PIN_NUM_RGB_DATA10,
ESP_PANEL_LCD_PIN_NUM_RGB_DATA11,
ESP_PANEL_LCD_PIN_NUM_RGB_DATA12,
ESP_PANEL_LCD_PIN_NUM_RGB_DATA13,
ESP_PANEL_LCD_PIN_NUM_RGB_DATA14,
ESP_PANEL_LCD_PIN_NUM_RGB_DATA15,
},
.flags = {
.disp_active_low = 0,
.refresh_on_demand = 0,
.fb_in_psram = true,
.double_fb = true,
.no_fb = 0,
.bb_invalidate_cache = 0,
},
};
esp_lcd_new_rgb_panel(&rgb_config, &panel_handle);
// esp_lcd_rgb_panel_event_callbacks_t cbs = {
// .on_vsync = example_on_vsync_event,
// };
// esp_lcd_rgb_panel_register_event_callbacks(panel_handle, &cbs, &disp_drv);
esp_lcd_panel_reset(panel_handle);
esp_lcd_panel_init(panel_handle);
}
bool example_on_vsync_event(esp_lcd_panel_handle_t panel, const esp_lcd_rgb_panel_event_data_t *event_data, void *user_data)
{
BaseType_t high_task_awoken = pdFALSE;
return high_task_awoken == pdTRUE;
}
void LCD_Init() {
ST7701_Reset();
ST7701_Init();
Touch_Init();
Backlight_Init();
}
void LCD_addWindow(uint16_t Xstart, uint16_t Ystart, uint16_t Xend, uint16_t Yend,uint8_t* color) {
Xend = Xend + 1; // esp_lcd_panel_draw_bitmap: x_end End index on x-axis (x_end not included)
Yend = Yend + 1; // esp_lcd_panel_draw_bitmap: y_end End index on y-axis (y_end not included)
if (Xend >= ESP_PANEL_LCD_WIDTH)
Xend = ESP_PANEL_LCD_WIDTH;
if (Yend >= ESP_PANEL_LCD_HEIGHT)
Yend = ESP_PANEL_LCD_HEIGHT;
esp_lcd_panel_draw_bitmap(panel_handle, Xstart, Ystart, Xend, Yend, color); // x_end End index on x-axis (x_end not included)
}
// backlight
uint8_t LCD_Backlight = 50;
void Backlight_Init()
{
ledcAttach(LCD_Backlight_PIN, Frequency, Resolution);
Set_Backlight(LCD_Backlight); //0~100
}
void Set_Backlight(uint8_t Light) //
{
if(Light > Backlight_MAX || Light < 0)
printf("Set Backlight parameters in the range of 0 to 100 \r\n");
else{
uint32_t Backlight = Light*10;
if(Backlight == 1000)
Backlight = 1024;
ledcWrite(LCD_Backlight_PIN, Backlight);
}
}
#pragma once
#include <inttypes.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/spi_master.h"
#include "driver/gpio.h"
#include "esp_heap_caps.h"
#include "esp_log.h"
#include "esp_lcd_panel_ops.h"
#include "esp_lcd_panel_io.h"
#include "esp_lcd_panel_rgb.h"
#include "driver/spi_master.h"
#include "driver/gpio.h"
#include "freertos/task.h"
#include "TCA9554PWR.h"
#include "Touch_CST820.h"
#define LCD_CLK_PIN 2
#define LCD_MOSI_PIN 1
#define LCD_Backlight_PIN 6
// Backlight
#define PWM_Channel 1 // PWM Channel
#define Frequency 20000 // PWM frequency
#define Resolution 10 // PWM resolution ratio MAX:13
#define Dutyfactor 500 // PWM Dutyfactor
#define Backlight_MAX 100
#define ESP_PANEL_LCD_WIDTH (480)
#define ESP_PANEL_LCD_HEIGHT (480)
#define ESP_PANEL_LCD_COLOR_BITS (16)
#define ESP_PANEL_LCD_RGB_PIXEL_BITS (16)
#define ESP_PANEL_LCD_RGB_DATA_WIDTH (16)
#define ESP_PANEL_LCD_RGB_TIMING_FREQ_HZ (16 * 1000 * 1000)
#define ESP_PANEL_LCD_RGB_TIMING_HPW (8)
#define ESP_PANEL_LCD_RGB_TIMING_HBP (10)
#define ESP_PANEL_LCD_RGB_TIMING_HFP (50)
#define ESP_PANEL_LCD_RGB_TIMING_VPW (3)
#define ESP_PANEL_LCD_RGB_TIMING_VBP (8)
#define ESP_PANEL_LCD_RGB_TIMING_VFP (8)
#define ESP_PANEL_LCD_RGB_FRAME_BUF_NUM (2)
#define ESP_PANEL_LCD_RGB_BOUNCE_BUF_SIZE (ESP_PANEL_LCD_WIDTH * 10)
// Pin definitions
#define ESP_PANEL_LCD_PIN_NUM_RGB_HSYNC (38)
#define ESP_PANEL_LCD_PIN_NUM_RGB_VSYNC (39)
#define ESP_PANEL_LCD_PIN_NUM_RGB_DE (40)
#define ESP_PANEL_LCD_PIN_NUM_RGB_PCLK (41)
#define ESP_PANEL_LCD_PIN_NUM_RGB_DATA0 (5)
#define ESP_PANEL_LCD_PIN_NUM_RGB_DATA1 (45)
#define ESP_PANEL_LCD_PIN_NUM_RGB_DATA2 (48)
#define ESP_PANEL_LCD_PIN_NUM_RGB_DATA3 (47)
#define ESP_PANEL_LCD_PIN_NUM_RGB_DATA4 (21)
#define ESP_PANEL_LCD_PIN_NUM_RGB_DATA5 (14)
#define ESP_PANEL_LCD_PIN_NUM_RGB_DATA6 (13)
#define ESP_PANEL_LCD_PIN_NUM_RGB_DATA7 (12)
#define ESP_PANEL_LCD_PIN_NUM_RGB_DATA8 (11)
#define ESP_PANEL_LCD_PIN_NUM_RGB_DATA9 (10)
#define ESP_PANEL_LCD_PIN_NUM_RGB_DATA10 (9)
#define ESP_PANEL_LCD_PIN_NUM_RGB_DATA11 (46)
#define ESP_PANEL_LCD_PIN_NUM_RGB_DATA12 (3)
#define ESP_PANEL_LCD_PIN_NUM_RGB_DATA13 (8)
#define ESP_PANEL_LCD_PIN_NUM_RGB_DATA14 (18)
#define ESP_PANEL_LCD_PIN_NUM_RGB_DATA15 (17)
#define ESP_PANEL_LCD_PIN_NUM_RGB_DISP (-1)
extern uint8_t LCD_Backlight;
extern esp_lcd_panel_handle_t panel_handle;
void LCD_Init();
void LCD_addWindow(uint16_t Xstart, uint16_t Ystart, uint16_t Xend, uint16_t Yend, uint8_t* color);
void Backlight_Init();
void Set_Backlight(uint8_t Light);
#include "I2C_Driver.h"
void I2C_Init(void) {
Wire.begin(I2C_SDA_PIN, I2C_SCL_PIN);
}
// 寄存器地址为 8 位的
bool I2C_Read(uint8_t Driver_addr, uint8_t Reg_addr, uint8_t *Reg_data, uint32_t Length)
{
Wire.beginTransmission(Driver_addr);
Wire.write(Reg_addr);
if ( Wire.endTransmission(true)){
printf("The I2C transmission fails. - I2C Read\r\n");
return -1;
}
Wire.requestFrom(Driver_addr, Length);
for (int i = 0; i < Length; i++) {
*Reg_data++ = Wire.read();
}
return 0;
}
bool I2C_Write(uint8_t Driver_addr, uint8_t Reg_addr, const uint8_t *Reg_data, uint32_t Length)
{
Wire.beginTransmission(Driver_addr);
Wire.write(Reg_addr);
for (int i = 0; i < Length; i++) {
Wire.write(*Reg_data++);
}
if ( Wire.endTransmission(true))
{
printf("The I2C transmission fails. - I2C Write\r\n");
return -1;
}
return 0;
}
#pragma once
#include <Wire.h>
#define I2C_SCL_PIN 7
#define I2C_SDA_PIN 15
void I2C_Init(void);
bool I2C_Read(uint8_t Driver_addr, uint8_t Reg_addr, uint8_t *Reg_data, uint32_t Length);
bool I2C_Write(uint8_t Driver_addr, uint8_t Reg_addr, const uint8_t *Reg_data, uint32_t Length);
#include <Arduino_GFX_Library.h>
#include "TCA9554PWR.h"
#include "Display_ST7701.h"
#include "Touch_CST820.h"
// Display dimensions
#define DISPLAY_WIDTH 480
#define DISPLAY_HEIGHT 480
// Color definitions
#define COLOR_BLACK 0x0000
#define COLOR_BLUE 0x001F
#define COLOR_RED 0xF800
#define COLOR_WHITE 0xFFFF
// Custom ST7701 Display Driver that uses existing initialization
class Arduino_ST7701 : public Arduino_GFX {
public:
Arduino_ST7701(Arduino_ESP32RGBPanel *panel, int16_t w = DISPLAY_WIDTH, int16_t h = DISPLAY_HEIGHT)
: Arduino_GFX(w, h), _panel(panel) {}
bool begin(int32_t speed = GFX_NOT_DEFINED) override {
_panel->begin();
LCD_Init();
return true;
}
protected:
void writePixelPreclipped(int16_t x, int16_t y, uint16_t color) override {
esp_lcd_panel_draw_bitmap(panel_handle, x, y, x + 1, y + 1, &color);
}
void writeFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color) override {
if (h < 0) {
y += h + 1;
h = -h;
}
uint16_t *line = (uint16_t *)malloc(h * sizeof(uint16_t));
if (line) {
for (int16_t i = 0; i < h; i++) {
line[i] = color;
}
esp_lcd_panel_draw_bitmap(panel_handle, x, y, x + 1, y + h, line);
free(line);
}
}
void writeFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color) override {
if (w < 0) {
x += w + 1;
w = -w;
}
uint16_t *line = (uint16_t *)malloc(w * sizeof(uint16_t));
if (line) {
for (int16_t i = 0; i < w; i++) {
line[i] = color;
}
esp_lcd_panel_draw_bitmap(panel_handle, x, y, x + w, y + 1, line);
free(line);
}
}
void writeFillRectPreclipped(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color) override {
if (w < 0) {
x += w + 1;
w = -w;
}
if (h < 0) {
y += h + 1;
h = -h;
}
uint16_t *buffer = (uint16_t *)malloc(w * h * sizeof(uint16_t));
if (buffer) {
for (int32_t i = 0; i < w * h; i++) {
buffer[i] = color;
}
esp_lcd_panel_draw_bitmap(panel_handle, x, y, x + w, y + h, buffer);
free(buffer);
}
}
private:
Arduino_ESP32RGBPanel* _panel;
};
// Error handling
enum InitStatus {
INIT_OK = 0,
INIT_I2C_FAILED,
INIT_IO_EXPANDER_FAILED,
INIT_DISPLAY_FAILED,
INIT_TOUCH_FAILED
};
// Create RGB Panel instance
Arduino_ESP32RGBPanel *rgbpanel = new Arduino_ESP32RGBPanel(
ESP_PANEL_LCD_PIN_NUM_RGB_DATA0, // B0
ESP_PANEL_LCD_PIN_NUM_RGB_DATA1, // B1
ESP_PANEL_LCD_PIN_NUM_RGB_DATA2, // B2
ESP_PANEL_LCD_PIN_NUM_RGB_DATA3, // B3
ESP_PANEL_LCD_PIN_NUM_RGB_DATA4, // B4
ESP_PANEL_LCD_PIN_NUM_RGB_DATA5, // G0
ESP_PANEL_LCD_PIN_NUM_RGB_DATA6, // G1
ESP_PANEL_LCD_PIN_NUM_RGB_DATA7, // G2
ESP_PANEL_LCD_PIN_NUM_RGB_DATA8, // G3
ESP_PANEL_LCD_PIN_NUM_RGB_DATA9, // G4
ESP_PANEL_LCD_PIN_NUM_RGB_DATA10, // G5
ESP_PANEL_LCD_PIN_NUM_RGB_DATA11, // R0
ESP_PANEL_LCD_PIN_NUM_RGB_DATA12, // R1
ESP_PANEL_LCD_PIN_NUM_RGB_DATA13, // R2
ESP_PANEL_LCD_PIN_NUM_RGB_DATA14, // R3
ESP_PANEL_LCD_PIN_NUM_RGB_DATA15, // R4
ESP_PANEL_LCD_PIN_NUM_RGB_PCLK, // PCLK
ESP_PANEL_LCD_PIN_NUM_RGB_VSYNC, // VSYNC
ESP_PANEL_LCD_PIN_NUM_RGB_HSYNC, // HSYNC
ESP_PANEL_LCD_PIN_NUM_RGB_DE, // DE
DISPLAY_WIDTH, // Width
DISPLAY_HEIGHT, // Height
16, // hsync_polarity
10, // hsync_front_porch
8, // hsync_pulse_width
50, // hsync_back_porch
3, // vsync_polarity
8, // vsync_front_porch
8, // vsync_pulse_width
8 // vsync_back_porch
);
// Create display driver instance
Arduino_ST7701 *gfx = new Arduino_ST7701(rgbpanel);
// Touch variables
volatile bool touch_enabled = false;
uint32_t last_touch_time = 0;
const uint32_t TOUCH_DEBOUNCE_MS = 50;
// Function prototypes
InitStatus initializeHardware();
void handleTouch();
void drawTouchPoint(uint16_t x, uint16_t y, bool pressed);
void IRAM_ATTR touchISR();
InitStatus initializeHardware() {
// Initialize I2C
Wire.begin(I2C_SDA_PIN, I2C_SCL_PIN);
delay(100);
// Initialize IO Expander
TCA9554PWR_Init(0x00);
uint8_t io_status = Read_EXIOS(TCA9554_OUTPUT_REG);
if (io_status == 0xFF) {
Serial.println("IO Expander initialization failed!");
return INIT_IO_EXPANDER_FAILED;
}
// Enable display power
Set_EXIO(EXIO_PIN8, Low);
delay(10);
// Initialize display using Arduino_GFX begin()
if (!static_cast<Arduino_GFX*>(gfx)->begin()) {
Serial.println("Display initialization failed!");
return INIT_DISPLAY_FAILED;
}
// Initialize touch controller
if (!Touch_Init()) {
Serial.println("Touch controller initialization failed!");
return INIT_TOUCH_FAILED;
}
// Set up touch interrupt
pinMode(CST820_INT_PIN, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(CST820_INT_PIN), touchISR, FALLING);
touch_enabled = true;
return INIT_OK;
}
void drawTouchPoint(uint16_t x, uint16_t y, bool pressed) {
const uint16_t radius = 5;
uint16_t color = pressed ? COLOR_RED : COLOR_BLUE;
if (!pressed) {
gfx->fillCircle(x, y, radius + 1, COLOR_BLUE);
return;
}
gfx->fillCircle(x, y, radius, color);
gfx->drawCircle(x, y, radius + 1, COLOR_WHITE);
}
void handleTouch() {
if (!touch_enabled) return;
uint32_t current_time = millis();
if (current_time - last_touch_time < TOUCH_DEBOUNCE_MS) return;
last_touch_time = current_time;
Touch_Read_Data();
if (touch_data.points > 0) {
uint16_t x = constrain(touch_data.x, 0, DISPLAY_WIDTH - 1);
uint16_t y = constrain(touch_data.y, 0, DISPLAY_HEIGHT - 1);
drawTouchPoint(x, y, true);
char buf[32];
snprintf(buf, sizeof(buf), "Touch: %d,%d ", x, y);
gfx->setTextColor(COLOR_WHITE, COLOR_BLUE);
gfx->setCursor(10, 10);
gfx->print(buf);
if (touch_data.gesture != NONE) {
gfx->setCursor(10, 30);
gfx->print("Gesture: ");
gfx->print(Touch_GestureName());
gfx->print(" ");
}
}
}
void IRAM_ATTR touchISR() {
Touch_CST820_ISR();
}
void setup() {
Serial.begin(115200);
Serial.println("ESP32-S3 Touch LCD Hello World");
InitStatus status = initializeHardware();
if (status != INIT_OK) {
Serial.print("Initialization failed with status: ");
Serial.println(status);
while (1) {
delay(1000);
Serial.print(".");
}
}
gfx->setRotation(0);
gfx->fillScreen(COLOR_BLUE);
gfx->setTextColor(COLOR_WHITE);
gfx->setTextSize(3);
const char* text = "Touch the screen!";
int16_t x1, y1;
uint16_t w, h;
gfx->getTextBounds(text, 0, 0, &x1, &y1, &w, &h);
int x = (DISPLAY_WIDTH - w) / 2;
int y = (DISPLAY_HEIGHT - h) / 2;
gfx->setCursor(x, y);
gfx->println(text);
Serial.println("Setup complete!");
}
void loop() {
handleTouch();
delay(10);
}
#include "TCA9554PWR.h"
/***************************************************** Operation register REG ****************************************************/
uint8_t I2C_Read_EXIO(uint8_t REG) // Read the value of the TCA9554PWR register REG
{
Wire.beginTransmission(TCA9554_ADDRESS);
Wire.write(REG);
uint8_t result = Wire.endTransmission();
if (result != 0) {
printf("The I2C transmission fails. - I2C Read EXIO\r\n");
}
Wire.requestFrom(TCA9554_ADDRESS, 1);
uint8_t bitsStatus;
if (Wire.available()) {
bitsStatus = Wire.read();
}
return bitsStatus;
}
uint8_t I2C_Write_EXIO(uint8_t REG,uint8_t Data) // Write Data to the REG register of the TCA9554PWR
{
Wire.beginTransmission(TCA9554_ADDRESS);
Wire.write(REG);
Wire.write(Data);
uint8_t result = Wire.endTransmission();
if (result != 0) {
printf("The I2C transmission fails. - I2C Write EXIO\r\n");
return -1;
}
return 0;
}
/********************************************************** Set EXIO mode **********************************************************/
void Mode_EXIO(uint8_t Pin,uint8_t State) // Set the mode of the TCA9554PWR Pin. The default is Output mode (output mode or input mode). State: 0= Output mode 1= input mode
{
uint8_t bitsStatus = I2C_Read_EXIO(TCA9554_CONFIG_REG);
uint8_t Data = (0x01 << (Pin-1)) | bitsStatus;
uint8_t result = I2C_Write_EXIO(TCA9554_CONFIG_REG,Data);
if (result != 0) {
printf("I/O Configuration Failure !!!\r\n");
}
}
void Mode_EXIOS(uint8_t PinState) // Set the mode of the 7 pins from the TCA9554PWR with PinState
{
uint8_t result = I2C_Write_EXIO(TCA9554_CONFIG_REG,PinState);
if (result != 0) {
printf("I/O Configuration Failure !!!\r\n");
}
}
/********************************************************** Read EXIO status **********************************************************/
uint8_t Read_EXIO(uint8_t Pin) // Read the level of the TCA9554PWR Pin
{
uint8_t inputBits = I2C_Read_EXIO(TCA9554_INPUT_REG);
uint8_t bitStatus = (inputBits >> (Pin-1)) & 0x01;
return bitStatus;
}
uint8_t Read_EXIOS(uint8_t REG = TCA9554_INPUT_REG) // Read the level of all pins of TCA9554PWR, the default read input level state, want to get the current IO output state, pass the parameter TCA9554_OUTPUT_REG, such as Read_EXIOS(TCA9554_OUTPUT_REG);
{
uint8_t inputBits = I2C_Read_EXIO(REG);
return inputBits;
}
/********************************************************** Set the EXIO output status **********************************************************/
void Set_EXIO(uint8_t Pin,uint8_t State) // Sets the level state of the Pin without affecting the other pins
{
uint8_t Data;
if(State < 2 && Pin < 9 && Pin > 0){
uint8_t bitsStatus = Read_EXIOS(TCA9554_OUTPUT_REG);
if(State == 1)
Data = (0x01 << (Pin-1)) | bitsStatus;
else if(State == 0)
Data = (~(0x01 << (Pin-1))) & bitsStatus;
uint8_t result = I2C_Write_EXIO(TCA9554_OUTPUT_REG,Data);
if (result != 0) {
printf("Failed to set GPIO!!!\r\n");
}
}
else
printf("Parameter error, please enter the correct parameter!\r\n");
}
void Set_EXIOS(uint8_t PinState) // Set 7 pins to the PinState state such as :PinState=0x23, 0010 0011 state (the highest bit is not used)
{
uint8_t result = I2C_Write_EXIO(TCA9554_OUTPUT_REG,PinState);
if (result != 0) {
printf("Failed to set GPIO!!!\r\n");
}
}
/********************************************************** Flip EXIO state **********************************************************/
void Set_Toggle(uint8_t Pin) // Flip the level of the TCA9554PWR Pin
{
uint8_t bitsStatus = Read_EXIO(Pin);
Set_EXIO(Pin,(bool)!bitsStatus);
}
/********************************************************* TCA9554PWR Initializes the device ***********************************************************/
void TCA9554PWR_Init(uint8_t PinState) // Set the seven pins to PinState state, for example :PinState=0x23, 0010 0011 State (Output mode or input mode) 0= Output mode 1= Input mode. The default value is output mode
{
Mode_EXIOS(PinState);
}
#pragma once
#include <stdio.h>
#include "I2C_Driver.h"
#define TCA9554_EXIO1 0x01
#define TCA9554_EXIO2 0x02
#define TCA9554_EXIO3 0x03
#define TCA9554_EXIO4 0x04
#define TCA9554_EXIO5 0x05
#define TCA9554_EXIO6 0x06
#define TCA9554_EXIO7 0x07
/****************************************************** The macro defines the TCA9554PWR information ******************************************************/
#define TCA9554_ADDRESS 0x20 // TCA9554PWR I2C address
// TCA9554PWR寄存器地址
#define TCA9554_INPUT_REG 0x00 // Input register,input level
#define TCA9554_OUTPUT_REG 0x01 // Output register, high and low level output
#define TCA9554_Polarity_REG 0x02 // The Polarity Inversion register (register 2) allows polarity inversion of pins defined as inputs by the Configuration register.
#define TCA9554_CONFIG_REG 0x03 // Configuration register, mode configuration
#define Low 0
#define High 1
#define EXIO_PIN1 1
#define EXIO_PIN2 2
#define EXIO_PIN3 3
#define EXIO_PIN4 4
#define EXIO_PIN5 5
#define EXIO_PIN6 6
#define EXIO_PIN7 7
#define EXIO_PIN8 8
/***************************************************** Operation register REG ****************************************************/
uint8_t I2C_Read_EXIO(uint8_t REG); // Read the value of the TCA9554PWR register REG
uint8_t I2C_Write_EXIO(uint8_t REG,uint8_t Data); // Write Data to the REG register of the TCA9554PWR
/********************************************************** Set EXIO mode **********************************************************/
void Mode_EXIO(uint8_t Pin,uint8_t State); // Set the mode of the TCA9554PWR Pin. The default is Output mode (output mode or input mode). State: 0= Output mode 1= input mode
void Mode_EXIOS(uint8_t PinState); // Set the mode of the 7 pins from the TCA9554PWR with PinState
/********************************************************** Read EXIO status **********************************************************/
uint8_t Read_EXIO(uint8_t Pin); // Read the level of the TCA9554PWR Pin
uint8_t Read_EXIOS(uint8_t REG); // Read the level of all pins of TCA9554PWR, the default read input level state, want to get the current IO output state, pass the parameter TCA9554_OUTPUT_REG, such as Read_EXIOS(TCA9554_OUTPUT_REG);
/********************************************************** Set the EXIO output status **********************************************************/
void Set_EXIO(uint8_t Pin,uint8_t State); // Sets the level state of the Pin without affecting the other pins
void Set_EXIOS(uint8_t PinState); // Set 7 pins to the PinState state such as :PinState=0x23, 0010 0011 state (the highest bit is not used)
/********************************************************** Flip EXIO state **********************************************************/
void Set_Toggle(uint8_t Pin); // Flip the level of the TCA9554PWR Pin
/********************************************************* TCA9554PWR Initializes the device ***********************************************************/
void TCA9554PWR_Init(uint8_t PinState = 0x00); // Set the seven pins to PinState state, for example :PinState=0x23, 0010 0011 State (the highest bit is not used) (Output mode or input mode) 0= Output mode 1= Input mode. The default value is output mode
#include "Touch_CST820.h"
bool I2C_Read_Touch(uint8_t Driver_addr, uint8_t Reg_addr, uint8_t *Reg_data, uint32_t Length)
{
Wire.beginTransmission(Driver_addr);
Wire.write(Reg_addr);
if ( Wire.endTransmission(true)){
printf("The I2C transmission fails. - I2C Read\r\n");
return -1;
}
Wire.requestFrom(Driver_addr, Length);
for (int i = 0; i < Length; i++) {
*Reg_data++ = Wire.read();
}
return 0;
}
bool I2C_Write_Touch(uint8_t Driver_addr, uint8_t Reg_addr, const uint8_t *Reg_data, uint32_t Length)
{
Wire.beginTransmission(Driver_addr);
Wire.write(Reg_addr);
for (int i = 0; i < Length; i++) {
Wire.write(*Reg_data++);
}
if ( Wire.endTransmission(true))
{
printf("The I2C transmission fails. - I2C Write\r\n");
return -1;
}
return 0;
}
struct CST820_Touch touch_data = {0};
uint8_t Touch_Init(void) {
pinMode(CST820_INT_PIN, INPUT_PULLUP);
CST820_Touch_Reset();
CST820_AutoSleep(false);
uint16_t Verification = CST820_Read_cfg();
// attachInterrupt(CST820_INT_PIN, Touch_CST820_ISR, interrupt);
return true;
}
/* Reset controller */
uint8_t CST820_Touch_Reset(void)
{
Set_EXIO(EXIO_PIN2,Low);
vTaskDelay(pdMS_TO_TICKS(10));
Set_EXIO(EXIO_PIN2,High);
vTaskDelay(pdMS_TO_TICKS(50));
return true;
}
uint16_t CST820_Read_cfg(void) {
uint8_t buf[3]={0};
I2C_Read_Touch(CST820_ADDR, CST820_REG_Version,buf, 1);
printf("TouchPad_Version:0x%02x\r\n", buf[0]);
I2C_Read_Touch(CST820_ADDR, CST820_REG_ChipID, buf, 3);
printf("ChipID:0x%02x ProjID:0x%02x FwVersion:0x%02x \r\n",buf[0], buf[1], buf[2]);
return true;
}
/*!
@brief Fall asleep automatically
*/
void CST820_AutoSleep(bool Sleep_State) {
CST820_Touch_Reset();
uint8_t Sleep_State_Set = 0;
if(Sleep_State)
Sleep_State_Set = 0;
else
Sleep_State_Set = 0xFF;
I2C_Write_Touch(CST820_ADDR, CST820_REG_DisAutoSleep, &Sleep_State_Set, 1);
}
// reads sensor and touches
// updates Touch Points
uint8_t Touch_Read_Data(void) {
uint8_t buf[6];
uint8_t touchpad_cnt = 0;
I2C_Read_Touch(CST820_ADDR, CST820_REG_GestureID, buf, 6);
/* touched gesture */
if (buf[0] != 0x00)
touch_data.gesture = (GESTURE)buf[0];
if (buf[1] != 0x00) {
noInterrupts();
/* Number of touched points */
touch_data.points = (uint8_t)buf[1];
if(touch_data.points > CST820_LCD_TOUCH_MAX_POINTS)
touch_data.points = CST820_LCD_TOUCH_MAX_POINTS;
/* Fill coordinates */
touch_data.x = ((buf[2] & 0x0F) << 8) + buf[3];
touch_data.y = ((buf[4] & 0x0F) << 8) + buf[5];
interrupts();
// printf(" points=%d \r\n",touch_data.points);
}
return true;
}
void example_touchpad_read(void){
Touch_Read_Data();
if (touch_data.gesture != NONE || touch_data.points != 0x00) {
// printf("Touch : X=%u Y=%u points=%d\r\n", touch_data.x , touch_data.y,touch_data.points);
} else {
// data->state = LV_INDEV_STATE_REL;
}
}
void Touch_Loop(void){
if(Touch_interrupts){
Touch_interrupts = false;
example_touchpad_read();
}
}
/*!
@brief handle interrupts
*/
uint8_t Touch_interrupts;
void IRAM_ATTR Touch_CST820_ISR(void) {
Touch_interrupts = true;
}
/*!
@brief get the gesture event name
*/
String Touch_GestureName(void) {
switch (touch_data.gesture) {
case NONE:
return "NONE";
break;
case SWIPE_DOWN:
return "SWIPE DOWN";
break;
case SWIPE_UP:
return "SWIPE UP";
break;
case SWIPE_LEFT:
return "SWIPE LEFT";
break;
case SWIPE_RIGHT:
return "SWIPE RIGHT";
break;
case SINGLE_CLICK:
return "SINGLE CLICK";
break;
case DOUBLE_CLICK:
return "DOUBLE CLICK";
break;
case LONG_PRESS:
return "LONG PRESS";
break;
default:
return "UNKNOWN";
break;
}
}
// Touch_CST820.h
#pragma once
#include "Arduino.h"
#include "I2C_Driver.h"
#include "TCA9554PWR.h"
#define CST820_ADDR 0x15
#define CST820_INT_PIN 16
#define CST820_LCD_TOUCH_MAX_POINTS (1)
enum GESTURE {
NONE = 0x00,
SWIPE_UP = 0x01,
SWIPE_DOWN = 0x02,
SWIPE_LEFT = 0x03,
SWIPE_RIGHT = 0x04,
SINGLE_CLICK = 0x05,
DOUBLE_CLICK = 0x0B,
LONG_PRESS = 0x0C
};
#define CST820_REG_Mode 0x00
#define CST820_REG_GestureID 0x01
#define CST820_REG_Version 0x15
#define CST820_REG_ChipID 0xA7
#define CST820_REG_ProjID 0xA8
#define CST820_REG_FwVersion 0xA9
#define CST820_REG_AutoSleepTime 0xF9
#define CST820_REG_DisAutoSleep 0xFE
extern uint8_t Touch_interrupts;
extern struct CST820_Touch {
uint8_t points; // Number of touch points
GESTURE gesture; // Gesture type
uint16_t x; // X coordinate
uint16_t y; // Y coordinate
} touch_data;
uint8_t Touch_Init();
uint8_t CST820_Touch_Reset(void);
void CST820_AutoSleep(bool Sleep_State);
uint16_t CST820_Read_cfg(void);
String Touch_GestureName(void);
uint8_t Touch_Read_Data(void);
void IRAM_ATTR Touch_CST820_ISR(void);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment