split udisplay.cpp into multiple files (#24007)

This commit is contained in:
Christian Baars 2025-10-12 17:15:02 +02:00 committed by GitHub
parent 23a89c1224
commit 0eec031d49
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 2923 additions and 3136 deletions

2980
lib/lib_display/UDisplay/uDisplay.cpp Executable file → Normal file

File diff suppressed because it is too large Load Diff

364
lib/lib_display/UDisplay/uDisplay.h Executable file → Normal file
View File

@ -10,20 +10,15 @@
#ifdef CONFIG_IDF_TARGET_ESP32S3
#define USE_ESP32_S3
#endif
#include "driver/spi_master.h"
#include "soc/gpio_periph.h"
#include <rom/gpio.h>
#include "driver/spi_master.h"
#endif
enum {
UT_RD,UT_RDM,UT_CP,UT_RTF,UT_MV,UT_MVB,UT_RT,UT_RTT,UT_RDW,UT_RDWM,UT_WR,UT_WRW,UT_CPR,UT_AND,UT_SCALE,UT_LIM,UT_DBG,UT_GSRT,UT_XPT,UT_CPM,UT_END
};
#define RA8876_DATA_WRITE 0x80
#define RA8876_DATA_READ 0xC0
#define RA8876_CMD_WRITE 0x00
#define RA8876_STATUS_READ 0x40
#define UDSP_WRITE_16 0xf0
#define UDSP_READ_DATA 0xf1
#define UDSP_READ_STATUS 0xf2
@ -41,13 +36,6 @@ enum {
#include <hal/lcd_hal.h>
#include <soc/lcd_cam_reg.h>
#include <soc/lcd_cam_struct.h>
static inline volatile uint32_t* get_gpio_hi_reg(int_fast8_t pin) { return (pin & 32) ? &GPIO.out1_w1ts.val : &GPIO.out_w1ts; }
//static inline volatile uint32_t* get_gpio_hi_reg(int_fast8_t pin) { return (volatile uint32_t*)((pin & 32) ? 0x60004014 : 0x60004008) ; } // workaround Eratta
static inline volatile uint32_t* get_gpio_lo_reg(int_fast8_t pin) { return (pin & 32) ? &GPIO.out1_w1tc.val : &GPIO.out_w1tc; }
//static inline volatile uint32_t* get_gpio_lo_reg(int_fast8_t pin) { return (volatile uint32_t*)((pin & 32) ? 0x60004018 : 0x6000400C) ; }
static inline bool gpio_in(int_fast8_t pin) { return ((pin & 32) ? GPIO.in1.data : GPIO.in) & (1 << (pin & 31)); }
static inline void gpio_hi(int_fast8_t pin) { if (pin >= 0) *get_gpio_hi_reg(pin) = 1 << (pin & 31); } // ESP_LOGI("LGFX", "gpio_hi: %d", pin); }
static inline void gpio_lo(int_fast8_t pin) { if (pin >= 0) *get_gpio_lo_reg(pin) = 1 << (pin & 31); } // ESP_LOGI("LGFX", "gpio_lo: %d", pin); }
#include "esp_lcd_panel_interface.h"
#include "esp_lcd_panel_rgb.h"
#include "esp_pm.h"
@ -72,65 +60,6 @@ static inline void gpio_lo(int_fast8_t pin) { if (pin >= 0) *get_gpio_lo_reg(pin
#define DISPLAY_INIT_PARTIAL 1
#define DISPLAY_INIT_FULL 2
enum uColorType { uCOLOR_BW, uCOLOR_COLOR };
// Color definitions
#define UDISP_BLACK 0x0000 /* 0, 0, 0 */
#define UDISP_NAVY 0x000F /* 0, 0, 128 */
#define UDISP_DARKGREEN 0x03E0 /* 0, 128, 0 */
#define UDISP_DARKCYAN 0x03EF /* 0, 128, 128 */
#define UDISP_MAROON 0x7800 /* 128, 0, 0 */
#define UDISP_PURPLE 0x780F /* 128, 0, 128 */
#define UDISP_OLIVE 0x7BE0 /* 128, 128, 0 */
#define UDISP_LIGHTGREY 0xC618 /* 192, 192, 192 */
#define UDISP_DARKGREY 0x7BEF /* 128, 128, 128 */
#define UDISP_BLUE 0x001F /* 0, 0, 255 */
#define UDISP_GREEN 0x07E0 /* 0, 255, 0 */
#define UDISP_CYAN 0x07FF /* 0, 255, 255 */
#define UDISP_RED 0xF800 /* 255, 0, 0 */
#define UDISP_MAGENTA 0xF81F /* 255, 0, 255 */
#define UDISP_YELLOW 0xFFE0 /* 255, 255, 0 */
#define UDISP_WHITE 0xFFFF /* 255, 255, 255 */
#define UDISP_ORANGE 0xFD20 /* 255, 165, 0 */
#define UDISP_GREENYELLOW 0xAFE5 /* 173, 255, 47 */
#define UDISP_PINK 0xFc18 /* 255, 128, 192 */
#ifdef ESP8266
#define PIN_OUT_SET 0x60000304
#define PIN_OUT_CLEAR 0x60000308
#define GPIO_SET(A) WRITE_PERI_REG( PIN_OUT_SET, 1 << A)
#define GPIO_CLR(A) WRITE_PERI_REG( PIN_OUT_CLEAR, 1 << A)
#define GPIO_CLR_SLOW(A) digitalWrite(A, LOW)
#define GPIO_SET_SLOW(A) digitalWrite(A, HIGH)
#else
#undef GPIO_SET
#undef GPIO_CLR
#undef GPIO_SET_SLOW
#undef GPIO_CLR_SLOW
#if CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C5 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32P4
#define GPIO_CLR(A) GPIO.out_w1tc.val = (1 << A)
#define GPIO_SET(A) GPIO.out_w1ts.val = (1 << A)
#else // plain ESP32
#define GPIO_CLR(A) GPIO.out_w1tc = (1 << A)
#define GPIO_SET(A) GPIO.out_w1ts = (1 << A)
#endif
#define GPIO_CLR_SLOW(A) digitalWrite(A, LOW)
#define GPIO_SET_SLOW(A) digitalWrite(A, HIGH)
#endif
#define SPI_BEGIN_TRANSACTION if (spi_nr <= 2) beginTransaction(spiSettings);
#define SPI_END_TRANSACTION if (spi_nr <= 2) endTransaction();
#define SPI_CS_LOW if (spi_cs >= 0) GPIO_CLR_SLOW(spi_cs);
#define SPI_CS_HIGH if (spi_cs >= 0) GPIO_SET_SLOW(spi_cs);
#define SPI_DC_LOW if (spi_dc >= 0) GPIO_CLR_SLOW(spi_dc);
#define SPI_DC_HIGH if (spi_dc >= 0) GPIO_SET_SLOW(spi_dc);
class uDisplay : public Renderer {
public:
@ -164,153 +93,154 @@ class uDisplay : public Renderer {
int16_t getPoint_y();
#endif // USE_UNIVERSAL_TOUCH
private:
void beginTransaction(SPISettings s);
void endTransaction(void);
void setAddrWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1);
void drawPixel(int16_t x, int16_t y, uint16_t color);
void drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color);
void drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color);
uint32_t str2c(char **sp, char *vp, uint32_t len);
void i2c_command(uint8_t val);
void ulcd_command_one(uint8_t val);
void ulcd_command(uint8_t val);
void ulcd_data8(uint8_t val);
void ulcd_data16(uint16_t val);
void ulcd_data32(uint32_t val);
void write8(uint8_t val);
void write8_slow(uint8_t val);
void write9(uint8_t val, uint8_t dc);
void write9_slow(uint8_t val, uint8_t dc);
void hw_write9(uint8_t val, uint8_t dc);
void write16(uint16_t val);
void write32(uint32_t val);
void spi_data9(uint8_t d, uint8_t dc);
uint8_t readData(void);
uint8_t readStatus(void);
uint8_t writeReg16(uint8_t reg, uint16_t wval);
void WriteColor(uint16_t color);
void SetLut(const unsigned char* lut);
void SetLuts(void);
void DisplayFrame_29(void);
void Updateframe_EPD();
//void DisplayFrame_42(const unsigned char* frame_buffer);
void SetFrameMemory(const unsigned char* image_buffer);
void SetFrameMemory(const unsigned char* image_buffer, uint16_t x, uint16_t y, uint16_t image_width, uint16_t image_height);
void SetMemoryArea(int x_start, int y_start, int x_end, int y_end);
void SetMemoryPointer(int x, int y);
void DrawAbsolutePixel(int x, int y, int16_t color);
void drawPixel_EPD(int16_t x, int16_t y, uint16_t color);
void fillRect_EPD(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color);
void drawFastVLine_EPD(int16_t x, int16_t y, int16_t h, uint16_t color);
void drawFastHLine_EPD(int16_t x, int16_t y, int16_t w, uint16_t color);
void Init_EPD(int8_t p);
void spi_command_EPD(uint8_t val);
void spi_data8_EPD(uint8_t val);
//void SetPartialWindow_42(uint8_t* frame_buffer, int16_t x, int16_t y, int16_t w, int16_t l, int16_t dtm);
void ClearFrameMemory(unsigned char color);
void ClearFrame_42(void);
void DisplayFrame_42(void);
uint8_t strlen_ln(char *str);
int32_t next_val(char **sp);
uint32_t next_hex(char **sp);
void setAddrWindow_int(uint16_t x, uint16_t y, uint16_t w, uint16_t h);
char dname[16];
int8_t bpp;
uint8_t col_type;
uint8_t interface;
uint8_t i2caddr;
int8_t i2c_scl;
int8_t spec_init;
TwoWire *wire;
int8_t wire_n;
int8_t i2c_sda;
uint8_t i2c_col_start;
uint8_t i2c_col_end;
uint8_t i2c_page_start;
uint8_t i2c_page_end;
int8_t reset;
uint8_t dsp_cmds[256];
uint8_t dsp_ncmds;
uint8_t dsp_on;
uint8_t dsp_off;
uint8_t allcmd_mode;
int8_t splash_font;
uint8_t splash_size;
uint16_t splash_xp;
uint16_t splash_yp;
uint16_t fg_col;
uint16_t bg_col;
uint16_t gxs;
uint16_t gys;
int8_t bpmode;
int8_t spi_cs;
int8_t spi_clk;
int8_t spi_mosi;
int8_t spi_dc;
int8_t bpanel; // backbanel GPIO, -1 if none
int8_t spi_miso;
uint8_t dimmer8; // 8 bits resolution, 0..255
uint16_t dimmer10_gamma; // 10 bits resolution, 0..1023, gamma corrected
SPIClass *uspi;
uint8_t sspi;
SPISettings spiSettings;
uint8_t spi_speed;
uint8_t spi_nr = 1;
uint8_t madctrl;
uint8_t startline;
uint8_t rot[4];
uint8_t rot_t[4];
uint16_t x_addr_offs[4];
uint16_t y_addr_offs[4];
uint8_t saw_1;
uint8_t saw_2;
uint8_t saw_3;
uint8_t cur_rot;
uint8_t col_mode;
uint8_t inv_on;
uint8_t inv_off;
uint8_t sa_mode;
uint8_t dim_op;
uint8_t lutfsize;
uint8_t lutpsize;
int16_t lutftime;
int8_t busy_pin;
uint16_t lutptime;
uint16_t lut3time;
uint16_t lut_num;
uint8_t ep_mode;
uint8_t ep_update_mode;
uint8_t *lut_full;
uint8_t lut_siz_full;
uint8_t *lut_partial;
uint8_t lut_siz_partial;
uint8_t *frame_buffer;
private:
uint8_t *frame_buffer;
uint8_t *lut_full;
uint8_t *lut_partial;
uint8_t *lut_array[MAX_LUTS];
uint8_t dsp_cmds[256];
char dname[16];
SPIClass *uspi;
TwoWire *wire;
SPISettings spiSettings;
uint8_t epcoffs_full;
uint8_t epc_full_cnt;
uint8_t epcoffs_part;
uint8_t epc_part_cnt;
uint16_t x_addr_offs[4];
uint16_t y_addr_offs[4];
uint16_t splash_xp;
uint16_t splash_yp;
uint16_t fg_col;
uint16_t bg_col;
uint16_t gxs;
uint16_t gys;
uint16_t dimmer10_gamma;
uint16_t seta_xp1;
uint16_t seta_xp2;
uint16_t seta_yp1;
uint16_t seta_yp2;
uint16_t lutptime;
uint16_t lut3time;
uint16_t lut_num;
uint8_t *lut_array[MAX_LUTS];
uint8_t lut_cnt[MAX_LUTS];
uint8_t lut_cmd[MAX_LUTS];
uint8_t lut_siz[MAX_LUTS];
uint16_t seta_xp1;
uint16_t seta_xp2;
uint16_t seta_yp1;
uint16_t seta_yp2;
int16_t rotmap_xmin;
int16_t rotmap_xmax;
int16_t rotmap_ymin;
int16_t rotmap_ymax;
void pushColorsMono(uint16_t *data, uint16_t len, bool rgb16_swap = false);
void delay_sync(int32_t time);
void reset_pin(int32_t delayl, int32_t delayh);
void delay_arg(uint32_t arg);
void Send_EP_Data(void);
void send_spi_cmds(uint16_t cmd_offset, uint16_t cmd_size);
void send_spi_icmds(uint16_t cmd_size);
uint8_t bpp;
uint8_t col_type;
uint8_t interface;
uint8_t i2caddr;
uint8_t i2c_col_start;
uint8_t i2c_col_end;
uint8_t i2c_page_start;
uint8_t i2c_page_end;
uint8_t dsp_ncmds;
uint8_t dsp_on;
uint8_t dsp_off;
uint8_t allcmd_mode;
uint8_t splash_size;
uint8_t dimmer8;
uint8_t spi_speed;
uint8_t spi_nr;
uint8_t rot[4];
uint8_t rot_t[4];
uint8_t madctrl;
uint8_t startline;
uint8_t saw_1;
uint8_t saw_2;
uint8_t saw_3;
uint8_t cur_rot;
uint8_t col_mode;
uint8_t inv_on;
uint8_t inv_off;
uint8_t sa_mode;
uint8_t dim_op;
uint8_t lutfsize;
uint8_t lutpsize;
uint8_t lut_siz_full;
uint8_t lut_siz_partial;
uint8_t epcoffs_full;
uint8_t epc_full_cnt;
uint8_t epcoffs_part;
uint8_t epc_part_cnt;
uint8_t lut_cnt[MAX_LUTS];
uint8_t lut_cmd[MAX_LUTS];
uint8_t lut_siz[MAX_LUTS];
uint8_t ep_mode;
uint8_t ep_update_mode;
uint8_t sspi;
int8_t spec_init;
int8_t wire_n;
int8_t i2c_scl;
int8_t i2c_sda;
int8_t reset;
int8_t splash_font;
int8_t bpmode;
int8_t spi_cs;
int8_t spi_clk;
int8_t spi_mosi;
int8_t spi_dc;
int8_t bpanel;
int8_t spi_miso;
int8_t busy_pin;
int16_t lutftime;
int16_t rotmap_xmin;
int16_t rotmap_xmax;
int16_t rotmap_ymin;
int16_t rotmap_ymax;
void beginTransaction(SPISettings s);
void endTransaction(void);
void setAddrWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1);
void drawPixel(int16_t x, int16_t y, uint16_t color);
void drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color);
void drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color);
uint32_t str2c(char **sp, char *vp, uint32_t len);
void i2c_command(uint8_t val);
void ulcd_command_one(uint8_t val);
void ulcd_command(uint8_t val);
void ulcd_data8(uint8_t val);
void ulcd_data16(uint16_t val);
void ulcd_data32(uint32_t val);
void write8(uint8_t val);
void write8_slow(uint8_t val);
void write9(uint8_t val, uint8_t dc);
void write9_slow(uint8_t val, uint8_t dc);
void hw_write9(uint8_t val, uint8_t dc);
void write16(uint16_t val);
void write32(uint32_t val);
void spi_data9(uint8_t d, uint8_t dc);
uint8_t readData(void);
uint8_t readStatus(void);
uint8_t writeReg16(uint8_t reg, uint16_t wval);
void WriteColor(uint16_t color);
void SetLut(const unsigned char* lut);
void SetLuts(void);
void DisplayFrame_29(void);
void Updateframe_EPD();
void SetFrameMemory(const unsigned char* image_buffer);
void SetFrameMemory(const unsigned char* image_buffer, uint16_t x, uint16_t y, uint16_t image_width, uint16_t image_height);
void SetMemoryArea(int x_start, int y_start, int x_end, int y_end);
void SetMemoryPointer(int x, int y);
void DrawAbsolutePixel(int x, int y, int16_t color);
void drawPixel_EPD(int16_t x, int16_t y, uint16_t color);
void fillRect_EPD(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color);
void drawFastVLine_EPD(int16_t x, int16_t y, int16_t h, uint16_t color);
void drawFastHLine_EPD(int16_t x, int16_t y, int16_t w, uint16_t color);
void Init_EPD(int8_t p);
void spi_command_EPD(uint8_t val);
void spi_data8_EPD(uint8_t val);
void ClearFrameMemory(unsigned char color);
void ClearFrame_42(void);
void DisplayFrame_42(void);
uint8_t strlen_ln(char *str);
int32_t next_val(char **sp);
uint32_t next_hex(char **sp);
void setAddrWindow_int(uint16_t x, uint16_t y, uint16_t w, uint16_t h);
void pushColorsMono(uint16_t *data, uint16_t len, bool rgb16_swap = false);
void delay_sync(int32_t time);
void reset_pin(int32_t delayl, int32_t delayh);
void delay_arg(uint32_t arg);
void Send_EP_Data(void);
void send_spi_cmds(uint16_t cmd_offset, uint16_t cmd_size);
void send_spi_icmds(uint16_t cmd_size);
#ifdef USE_ESP32_S3

View File

@ -0,0 +1,31 @@
#include "uDisplay.h"
#include "uDisplay_config.h"
// Color palette definition
static constexpr uint16_t udisp_colors[] = {
UDISP_BLACK, UDISP_WHITE, UDISP_RED, UDISP_GREEN, UDISP_BLUE, UDISP_CYAN,
UDISP_MAGENTA, UDISP_YELLOW, UDISP_NAVY, UDISP_DARKGREEN, UDISP_DARKCYAN,
UDISP_MAROON, UDISP_PURPLE, UDISP_OLIVE, UDISP_LIGHTGREY, UDISP_DARKGREY,
UDISP_ORANGE, UDISP_GREENYELLOW, UDISP_PINK
};
uint16_t uDisplay::GetColorFromIndex(uint8_t index) {
const size_t color_count = sizeof(udisp_colors) / sizeof(udisp_colors[0]);
if (index >= color_count) {
index = 0;
}
return udisp_colors[index];
}
uint16_t uDisplay::fgcol(void) {
return fg_col;
}
uint16_t uDisplay::bgcol(void) {
return bg_col;
}
int8_t uDisplay::color_type(void) {
return col_type;
}

View File

@ -0,0 +1,56 @@
#ifndef UDISPLAY_CONFIG_H
#define UDISPLAY_CONFIG_H
// Logging system interface
enum LoggingLevels {
LOG_LEVEL_NONE,
LOG_LEVEL_ERROR,
LOG_LEVEL_INFO,
LOG_LEVEL_DEBUG,
LOG_LEVEL_DEBUG_MORE
};
extern void AddLog(uint32_t loglevel, const char* formatP, ...);
extern int32_t ESP_ResetInfoReason();
extern float CharToFloat(const char *str);
extern SPIClass *SpiBegin(uint32 bus);
extern int Cache_WriteBack_Addr(uint32_t addr, uint32_t size);
extern bool UsePSRAM(void);
enum uColorType { uCOLOR_BW, uCOLOR_COLOR };
// Color definitions
constexpr uint16_t UDISP_BLACK = 0x0000; /* 0, 0, 0 */
constexpr uint16_t UDISP_NAVY = 0x000F; /* 0, 0, 128 */
constexpr uint16_t UDISP_DARKGREEN = 0x03E0; /* 0, 128, 0 */
constexpr uint16_t UDISP_DARKCYAN = 0x03EF; /* 0, 128, 128 */
constexpr uint16_t UDISP_MAROON = 0x7800; /* 128, 0, 0 */
constexpr uint16_t UDISP_PURPLE = 0x780F; /* 128, 0, 128 */
constexpr uint16_t UDISP_OLIVE = 0x7BE0; /* 128, 128, 0 */
constexpr uint16_t UDISP_LIGHTGREY = 0xC618; /* 192, 192, 192 */
constexpr uint16_t UDISP_DARKGREY = 0x7BEF; /* 128, 128, 128 */
constexpr uint16_t UDISP_BLUE = 0x001F; /* 0, 0, 255 */
constexpr uint16_t UDISP_GREEN = 0x07E0; /* 0, 255, 0 */
constexpr uint16_t UDISP_CYAN = 0x07FF; /* 0, 255, 255 */
constexpr uint16_t UDISP_RED = 0xF800; /* 255, 0, 0 */
constexpr uint16_t UDISP_MAGENTA = 0xF81F; /* 255, 0, 255 */
constexpr uint16_t UDISP_YELLOW = 0xFFE0; /* 255, 255, 0 */
constexpr uint16_t UDISP_WHITE = 0xFFFF; /* 255, 255, 255 */
constexpr uint16_t UDISP_ORANGE = 0xFD20; /* 255, 165, 0 */
constexpr uint16_t UDISP_GREENYELLOW = 0xAFE5; /* 173, 255, 47 */
constexpr uint16_t UDISP_PINK = 0xFC18; /* 255, 128, 192 */
// epaper pseudo opcodes
constexpr uint8_t EP_RESET = 0x60;
constexpr uint8_t EP_LUT_FULL = 0x61;
constexpr uint8_t EP_LUT_PARTIAL = 0x62;
constexpr uint8_t EP_WAITIDLE = 0x63;
constexpr uint8_t EP_SET_MEM_AREA = 0x64;
constexpr uint8_t EP_SET_MEM_PTR = 0x65;
constexpr uint8_t EP_SEND_DATA = 0x66;
constexpr uint8_t EP_CLR_FRAME = 0x67;
constexpr uint8_t EP_SEND_FRAME = 0x68;
constexpr uint8_t EP_BREAK_RR_EQU = 0x69;
constexpr uint8_t EP_BREAK_RR_NEQ = 0x6a;
#endif

View File

@ -0,0 +1,146 @@
#include "uDisplay.h"
#include "uDisplay_config.h"
#include "uDisplay_spi.h"
void udisp_bpwr(uint8_t on);
void udisp_dimm(uint8_t dim);
// input value is 0..15
// void uDisplay::dim(uint8_t dim) {
// dim8(((uint32_t)dim * 255) / 15);
// }
// ===== Power Management =====
void uDisplay::DisplayOnff(int8_t on) {
if (ep_mode) {
return;
}
if (pwr_cbp) {
pwr_cbp(on);
}
#define AW_PWMRES 1024
if (interface == _UDSP_I2C) {
if (on) {
i2c_command(dsp_on);
} else {
i2c_command(dsp_off);
}
} else {
if (on) {
if (dsp_on != 0xff) ulcd_command_one(dsp_on);
if (bpanel >= 0) {
#ifdef ESP32
if (!bpmode) {
analogWrite(bpanel, dimmer10_gamma);
} else {
analogWrite(bpanel, AW_PWMRES - dimmer10_gamma);
}
#else
if (!bpmode) {
digitalWrite(bpanel, HIGH);
} else {
digitalWrite(bpanel, LOW);
}
#endif
}
} else {
if (dsp_off != 0xff) ulcd_command_one(dsp_off);
if (bpanel >= 0) {
#ifdef ESP32
if (!bpmode) {
analogWrite(bpanel, 0);
} else {
analogWrite(bpanel, AW_PWMRES - 1);
}
#else
if (!bpmode) {
digitalWrite(bpanel, LOW);
} else {
digitalWrite(bpanel, HIGH);
}
#endif
}
}
}
}
// ===== Brightness/Dimming Control =====
// dim is 0..255
void uDisplay::dim10(uint8_t dim, uint16_t dim_gamma) {
dimmer8 = dim;
dimmer10_gamma = dim_gamma;
if (ep_mode) {
return;
}
#ifdef ESP32
if (bpanel >= 0) {
if (!bpmode) {
analogWrite(bpanel, dimmer10_gamma);
} else {
analogWrite(bpanel, AW_PWMRES - dimmer10_gamma);
}
} else if (dim_cbp) {
dim_cbp(dim);
}
#endif
if (interface == _UDSP_SPI) {
if (dim_op != 0xff) {
SPI_BEGIN_TRANSACTION
SPI_CS_LOW
ulcd_command(dim_op);
ulcd_data8(dimmer8);
SPI_CS_HIGH
SPI_END_TRANSACTION
}
}
}
// ===== Display Inversion =====
void uDisplay::invertDisplay(boolean i) {
if (ep_mode) {
return;
}
if (interface == _UDSP_SPI || interface == _UDSP_PAR8 || interface == _UDSP_PAR16) {
if (i) {
ulcd_command_one(inv_on);
} else {
ulcd_command_one(inv_off);
}
}
if (interface == _UDSP_I2C) {
if (i) {
i2c_command(inv_on);
} else {
i2c_command(inv_off);
}
}
}
// ===== Splash Screen =====
void uDisplay::Splash(void) {
if (splash_font < 0) return;
if (ep_mode) {
Updateframe();
delay_sync(lut3time * 10);
}
setTextFont(splash_font);
setTextSize(splash_size);
DrawStringAt(splash_xp, splash_yp, dname, fg_col, 0);
Updateframe();
AddLog(LOG_LEVEL_DEBUG, PSTR("DSP: draw splash"));
}

View File

@ -0,0 +1,133 @@
#include "uDisplay.h"
#include "uDisplay_config.h"
#ifdef ESP32
// ===== DMA Initialization and Control =====
// ESP 32 DMA section , derived from TFT_eSPI
bool uDisplay::initDMA(int32_t ctrl_cs) {
if (DMA_Enabled) return false;
esp_err_t ret;
spi_bus_config_t buscfg = {
.mosi_io_num = spi_mosi,
.miso_io_num = -1,
.sclk_io_num = spi_clk,
.quadwp_io_num = -1,
.quadhd_io_num = -1,
.max_transfer_sz = width() * height() * 2 + 8, // TFT screen size
.flags = 0,
.intr_flags = 0
};
spi_device_interface_config_t devcfg = {
.command_bits = 0,
.address_bits = 0,
.dummy_bits = 0,
.mode = SPI_MODE3,
.duty_cycle_pos = 0,
.cs_ena_pretrans = 0,
.cs_ena_posttrans = 0,
.clock_speed_hz = spi_speed*1000000,
.input_delay_ns = 0,
.spics_io_num = ctrl_cs,
.flags = SPI_DEVICE_NO_DUMMY, //0,
.queue_size = 1,
.pre_cb = 0, //dc_callback, //Callback to handle D/C line
.post_cb = 0
};
ret = spi_bus_initialize(spi_host, &buscfg, 1);
ESP_ERROR_CHECK(ret);
ret = spi_bus_add_device(spi_host, &devcfg, &dmaHAL);
ESP_ERROR_CHECK(ret);
DMA_Enabled = true;
spiBusyCheck = 0;
return true;
}
void uDisplay::deInitDMA(void) {
if (!DMA_Enabled) return;
spi_bus_remove_device(dmaHAL);
spi_bus_free(spi_host);
DMA_Enabled = false;
}
bool uDisplay::dmaBusy(void) {
if (!DMA_Enabled || !spiBusyCheck) return false;
spi_transaction_t *rtrans;
esp_err_t ret;
uint8_t checks = spiBusyCheck;
for (int i = 0; i < checks; ++i) {
ret = spi_device_get_trans_result(dmaHAL, &rtrans, 0);
if (ret == ESP_OK) spiBusyCheck--;
}
//Serial.print("spiBusyCheck=");Serial.println(spiBusyCheck);
if (spiBusyCheck == 0) return false;
return true;
}
void uDisplay::dmaWait(void) {
if (!DMA_Enabled || !spiBusyCheck) return;
spi_transaction_t *rtrans;
esp_err_t ret;
for (int i = 0; i < spiBusyCheck; ++i) {
ret = spi_device_get_trans_result(dmaHAL, &rtrans, portMAX_DELAY);
assert(ret == ESP_OK);
}
spiBusyCheck = 0;
}
// ===== DMA Data Transfer Functions =====
void uDisplay::pushPixelsDMA(uint16_t* image, uint32_t len) {
if ((len == 0) || (!DMA_Enabled)) return;
dmaWait();
esp_err_t ret;
memset(&trans, 0, sizeof(spi_transaction_t));
trans.user = (void *)1;
trans.tx_buffer = image; //finally send the line data
trans.length = len * 16; //Data length, in bits
trans.flags = 0; //SPI_TRANS_USE_TXDATA flag
ret = spi_device_queue_trans(dmaHAL, &trans, portMAX_DELAY);
assert(ret == ESP_OK);
spiBusyCheck++;
if (!lvgl_param.async_dma) {
dmaWait();
}
}
void uDisplay::pushPixels3DMA(uint8_t* image, uint32_t len) {
if ((len == 0) || (!DMA_Enabled)) return;
dmaWait();
esp_err_t ret;
memset(&trans, 0, sizeof(spi_transaction_t));
trans.user = (void *)1;
trans.tx_buffer = image; //finally send the line data
trans.length = len * 24; //Data length, in bits
trans.flags = 0; //SPI_TRANS_USE_TXDATA flag
ret = spi_device_queue_trans(dmaHAL, &trans, portMAX_DELAY);
assert(ret == ESP_OK);
spiBusyCheck++;
if (!lvgl_param.async_dma) {
dmaWait();
}
}
#endif // ESP32

View File

@ -0,0 +1,362 @@
#include "uDisplay.h"
#include "uDisplay_config.h"
#include "uDisplay_spi.h"
// ===== EPD Command Definitions =====
static constexpr uint8_t DRIVER_OUTPUT_CONTROL = 0x01;
static constexpr uint8_t BOOSTER_SOFT_START_CONTROL = 0x0C;
static constexpr uint8_t GATE_SCAN_START_POSITION = 0x0F;
static constexpr uint8_t DEEP_SLEEP_MODE = 0x10;
static constexpr uint8_t DATA_ENTRY_MODE_SETTING = 0x11;
static constexpr uint8_t SW_RESET = 0x12;
static constexpr uint8_t TEMPERATURE_SENSOR_CONTROL = 0x1A;
static constexpr uint8_t MASTER_ACTIVATION = 0x20;
static constexpr uint8_t DISPLAY_UPDATE_CONTROL_1 = 0x21;
static constexpr uint8_t DISPLAY_UPDATE_CONTROL_2 = 0x22;
static constexpr uint8_t WRITE_RAM = 0x24;
static constexpr uint8_t WRITE_VCOM_REGISTER = 0x2C;
static constexpr uint8_t WRITE_LUT_REGISTER = 0x32;
static constexpr uint8_t SET_DUMMY_LINE_PERIOD = 0x3A;
static constexpr uint8_t SET_GATE_TIME = 0x3B;
static constexpr uint8_t BORDER_WAVEFORM_CONTROL = 0x3C;
static constexpr uint8_t SET_RAM_X_ADDRESS_START_END_POSITION = 0x44;
static constexpr uint8_t SET_RAM_Y_ADDRESS_START_END_POSITION = 0x45;
static constexpr uint8_t SET_RAM_X_ADDRESS_COUNTER = 0x4E;
static constexpr uint8_t SET_RAM_Y_ADDRESS_COUNTER = 0x4F;
static constexpr uint8_t TERMINATE_FRAME_READ_WRITE = 0xFF;
// ===== EPD Initialization and Control =====
void uDisplay::Init_EPD(int8_t p) {
if (p == DISPLAY_INIT_PARTIAL) {
if (lutpsize) {
AddLog(LOG_LEVEL_DEBUG, PSTR("DSP: init partial epaper mode"));
SetLut(lut_partial);
Updateframe_EPD();
delay_sync(lutptime * 10);
}
return;
} else if (p == DISPLAY_INIT_FULL) {
AddLog(LOG_LEVEL_DEBUG, PSTR("DSP: init full epaper mode"));
if (lutfsize) {
SetLut(lut_full);
Updateframe_EPD();
}
if (ep_mode == 2) {
ClearFrame_42();
DisplayFrame_42();
}
delay_sync(lutftime * 10);
return;
}
if (ep_mode == 2) Init_EPD(DISPLAY_INIT_FULL);
}
void uDisplay::SetLut(const unsigned char* lut) {
spi_command_EPD(lut_cmd[0]);
for (int i = 0; i < lutfsize; i++) {
spi_data8_EPD(lut[i]);
}
}
void uDisplay::SetLuts(void) {
uint8_t index, count;
for (index = 0; index < MAX_LUTS; index++) {
spi_command_EPD(lut_cmd[index]);
for (count = 0; count < lut_cnt[index]; count++) {
spi_data8_EPD(lut_array[index][count]);
}
}
}
// ===== EPD Frame Memory Management =====
void uDisplay::ClearFrameMemory(unsigned char color) {
SetMemoryArea(0, 0, gxs - 1, gys - 1);
SetMemoryPointer(0, 0);
spi_command_EPD(WRITE_RAM);
for (int i = 0; i < gxs / 8 * gys; i++) {
spi_data8_EPD(color);
}
}
void uDisplay::ClearFrame_42(void) {
spi_command_EPD(saw_1);
for (uint16_t j = 0; j < gys; j++) {
for (uint16_t i = 0; i < gxs; i++) {
spi_data8_EPD(0xFF);
}
}
spi_command_EPD(saw_2);
for (uint16_t j = 0; j < gys; j++) {
for (uint16_t i = 0; i < gxs; i++) {
spi_data8_EPD(0xFF);
}
}
spi_command_EPD(saw_3);
delay_sync(100);
AddLog(LOG_LEVEL_DEBUG, PSTR("DSP: EPD Clearframe"));
}
void uDisplay::DisplayFrame_42(void) {
spi_command_EPD(saw_1);
for(int i = 0; i < gxs / 8 * gys; i++) {
spi_data8_EPD(0xFF);
}
delay(2);
spi_command_EPD(saw_2);
for(int i = 0; i < gxs / 8 * gys; i++) {
spi_data8_EPD(framebuffer[i]^0xff);
}
delay(2);
SetLuts();
spi_command_EPD(saw_3);
delay_sync(100);
AddLog(LOG_LEVEL_DEBUG, PSTR("DSP: EPD Displayframe"));
}
void uDisplay::DisplayFrame_29(void) {
spi_command_EPD(DISPLAY_UPDATE_CONTROL_2);
spi_data8_EPD(0xC4);
spi_command_EPD(MASTER_ACTIVATION);
spi_data8_EPD(TERMINATE_FRAME_READ_WRITE);
}
// ===== EPD Memory Addressing =====
void uDisplay::SetMemoryArea(int x_start, int y_start, int x_end, int y_end) {
int x_start1 = (x_start >> 3) & 0xFF;
int x_end1 = (x_end >> 3) & 0xFF;
int y_start1 = y_start & 0xFF;
int y_start2 = (y_start >> 8) & 0xFF;
int y_end1 = y_end & 0xFF;
int y_end2 = (y_end >> 8) & 0xFF;
if (ep_mode == 3) {
spi_command_EPD(SET_RAM_X_ADDRESS_START_END_POSITION);
spi_data8_EPD(x_start1);
spi_data8_EPD(x_end1);
spi_command_EPD(SET_RAM_Y_ADDRESS_START_END_POSITION);
spi_data8_EPD(y_end1);
spi_data8_EPD(y_end2);
spi_data8_EPD(y_start1);
spi_data8_EPD(y_start2);
} else {
spi_command_EPD(SET_RAM_X_ADDRESS_START_END_POSITION);
spi_data8_EPD(x_start1);
spi_data8_EPD(x_end1);
spi_command_EPD(SET_RAM_Y_ADDRESS_START_END_POSITION);
spi_data8_EPD(y_start1);
spi_data8_EPD(y_start2);
spi_data8_EPD(y_end1);
spi_data8_EPD(y_end2);
}
}
void uDisplay::SetMemoryPointer(int x, int y) {
int x1;
int y1;
int y2;
if (ep_mode == 3) {
x1 = (x >> 3) & 0xFF;
y--;
y1 = y & 0xFF;
y2 = (y >> 8) & 0xFF;
} else {
x1 = (x >> 3) & 0xFF;
y1 = y & 0xFF;
y2 = (y >> 8) & 0xFF;
}
spi_command_EPD(SET_RAM_X_ADDRESS_COUNTER);
spi_data8_EPD(x1);
spi_command_EPD(SET_RAM_Y_ADDRESS_COUNTER);
spi_data8_EPD(y1);
spi_data8_EPD(y2);
}
// ===== EPD Frame Updates =====
void uDisplay::Updateframe_EPD(void) {
if (ep_mode == 1 || ep_mode == 3) {
switch (ep_update_mode) {
case DISPLAY_INIT_PARTIAL:
if (epc_part_cnt) {
send_spi_cmds(epcoffs_part, epc_part_cnt);
}
break;
case DISPLAY_INIT_FULL:
if (epc_full_cnt) {
send_spi_cmds(epcoffs_full, epc_full_cnt);
}
break;
default:
SetFrameMemory(framebuffer, 0, 0, gxs, gys);
DisplayFrame_29();
}
} else {
DisplayFrame_42();
}
}
void uDisplay::SetFrameMemory(const unsigned char* image_buffer) {
SetMemoryArea(0, 0, gxs - 1, gys - 1);
SetMemoryPointer(0, 0);
spi_command_EPD(WRITE_RAM);
for (int i = 0; i < gxs / 8 * gys; i++) {
spi_data8_EPD(image_buffer[i] ^ 0xff);
}
}
void uDisplay::SetFrameMemory(const unsigned char* image_buffer,
uint16_t x, uint16_t y, uint16_t image_width, uint16_t image_height) {
uint16_t x_end;
uint16_t y_end;
if (image_buffer == NULL || x < 0 || image_width < 0 || y < 0 || image_height < 0) {
return;
}
x &= 0xFFF8;
image_width &= 0xFFF8;
if (x + image_width >= gxs) {
x_end = gxs - 1;
} else {
x_end = x + image_width - 1;
}
if (y + image_height >= gys) {
y_end = gys - 1;
} else {
y_end = y + image_height - 1;
}
if (!x && !y && image_width == gxs && image_height == gys) {
SetFrameMemory(image_buffer);
return;
}
SetMemoryArea(x, y, x_end, y_end);
SetMemoryPointer(x, y);
spi_command_EPD(WRITE_RAM);
for (uint16_t j = 0; j < y_end - y + 1; j++) {
for (uint16_t i = 0; i < (x_end - x + 1) / 8; i++) {
spi_data8_EPD(image_buffer[i + j * (image_width / 8)] ^ 0xff);
}
}
}
void uDisplay::Send_EP_Data() {
uint16_t image_width = gxs & 0xFFF8;
uint16_t x = 0;
uint16_t y = 0;
uint16_t x_end = gxs - 1;
uint16_t y_end = gys - 1;
for (uint16_t j = 0; j < y_end - y + 1; j++) {
for (uint16_t i = 0; i < (x_end - x + 1) / 8; i++) {
spi_data8_EPD(framebuffer[i + j * (image_width / 8)] ^ 0xff);
}
}
}
// ===== EPD Drawing Primitives =====
#define IF_INVERT_COLOR 1
#define renderer_swap(a, b) { int16_t t = a; a = b; b = t; }
void uDisplay::DrawAbsolutePixel(int x, int y, int16_t color) {
int16_t w = width(), h = height();
if (cur_rot == 1 || cur_rot == 3) {
renderer_swap(w, h);
}
if (x < 0 || x >= w || y < 0 || y >= h) {
return;
}
if (IF_INVERT_COLOR) {
if (color) {
framebuffer[(x + y * w) / 8] |= 0x80 >> (x % 8);
} else {
framebuffer[(x + y * w) / 8] &= ~(0x80 >> (x % 8));
}
} else {
if (color) {
framebuffer[(x + y * w) / 8] &= ~(0x80 >> (x % 8));
} else {
framebuffer[(x + y * w) / 8] |= 0x80 >> (x % 8);
}
}
}
void uDisplay::drawPixel_EPD(int16_t x, int16_t y, uint16_t color) {
if (!framebuffer) return;
if ((x < 0) || (x >= width()) || (y < 0) || (y >= height()))
return;
switch (cur_rot) {
case 1:
renderer_swap(x, y);
x = gxs - x - 1;
break;
case 2:
x = gxs - x - 1;
y = gys - y - 1;
break;
case 3:
renderer_swap(x, y);
y = gys - y - 1;
break;
}
DrawAbsolutePixel(x, y, color);
}
void uDisplay::fillRect_EPD(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color) {
for (uint32_t yp = y; yp < y + h; yp++) {
for (uint32_t xp = x; xp < x + w; xp++) {
drawPixel_EPD(xp, yp, color);
}
}
}
void uDisplay::drawFastVLine_EPD(int16_t x, int16_t y, int16_t h, uint16_t color) {
while (h--) {
drawPixel_EPD(x, y, color);
y++;
}
}
void uDisplay::drawFastHLine_EPD(int16_t x, int16_t y, int16_t w, uint16_t color) {
while (w--) {
drawPixel_EPD(x, y, color);
x++;
}
}
// ===== EPD SPI Helpers =====
void uDisplay::spi_command_EPD(uint8_t val) {
SPI_BEGIN_TRANSACTION
SPI_CS_LOW
ulcd_command(val);
SPI_CS_HIGH
SPI_END_TRANSACTION
}
void uDisplay::spi_data8_EPD(uint8_t val) {
SPI_BEGIN_TRANSACTION
SPI_CS_LOW
ulcd_data8(val);
SPI_CS_HIGH
SPI_END_TRANSACTION
}

View File

@ -0,0 +1,158 @@
#include "uDisplay.h"
#include "uDisplay_config.h"
#ifdef USE_ESP32_S3
static inline volatile uint32_t* get_gpio_hi_reg(int_fast8_t pin) { return (pin & 32) ? &GPIO.out1_w1ts.val : &GPIO.out_w1ts; }
//static inline volatile uint32_t* get_gpio_hi_reg(int_fast8_t pin) { return (volatile uint32_t*)((pin & 32) ? 0x60004014 : 0x60004008) ; } // workaround Eratta
static inline volatile uint32_t* get_gpio_lo_reg(int_fast8_t pin) { return (pin & 32) ? &GPIO.out1_w1tc.val : &GPIO.out_w1tc; }
//static inline volatile uint32_t* get_gpio_lo_reg(int_fast8_t pin) { return (volatile uint32_t*)((pin & 32) ? 0x60004018 : 0x6000400C) ; }
static inline bool gpio_in(int_fast8_t pin) { return ((pin & 32) ? GPIO.in1.data : GPIO.in) & (1 << (pin & 31)); }
static inline void gpio_hi(int_fast8_t pin) { if (pin >= 0) *get_gpio_hi_reg(pin) = 1 << (pin & 31); } // ESP_LOGI("LGFX", "gpio_hi: %d", pin); }
static inline void gpio_lo(int_fast8_t pin) { if (pin >= 0) *get_gpio_lo_reg(pin) = 1 << (pin & 31); } // ESP_LOGI("LGFX", "gpio_lo: %d", pin); }
// ===== ESP32-S3 Clock Calculation =====
void uDisplay::calcClockDiv(uint32_t* div_a, uint32_t* div_b, uint32_t* div_n, uint32_t* clkcnt, uint32_t baseClock, uint32_t targetFreq) {
uint32_t diff = INT32_MAX;
*div_n = 256;
*div_a = 63;
*div_b = 62;
*clkcnt = 64;
uint32_t start_cnt = std::min<uint32_t>(64u, (baseClock / (targetFreq * 2) + 1));
uint32_t end_cnt = std::max<uint32_t>(2u, baseClock / 256u / targetFreq);
if (start_cnt <= 2) { end_cnt = 1; }
for (uint32_t cnt = start_cnt; diff && cnt >= end_cnt; --cnt)
{
float fdiv = (float)baseClock / cnt / targetFreq;
uint32_t n = std::max<uint32_t>(2u, (uint32_t)fdiv);
fdiv -= n;
for (uint32_t a = 63; diff && a > 0; --a)
{
uint32_t b = roundf(fdiv * a);
if (a == b && n == 256) {
break;
}
uint32_t freq = baseClock / ((n * cnt) + (float)(b * cnt) / (float)a);
uint32_t d = abs((int)targetFreq - (int)freq);
if (diff <= d) { continue; }
diff = d;
*clkcnt = cnt;
*div_n = n;
*div_b = b;
*div_a = a;
if (b == 0 || a == b) {
break;
}
}
}
if (*div_a == *div_b)
{
*div_b = 0;
*div_n += 1;
}
}
// ===== ESP32-S3 DMA Descriptor Management =====
void uDisplay::_alloc_dmadesc(size_t len) {
if (_dmadesc) heap_caps_free(_dmadesc);
_dmadesc_size = len;
_dmadesc = (lldesc_t*)heap_caps_malloc(sizeof(lldesc_t) * len, MALLOC_CAP_DMA);
}
void uDisplay::_setup_dma_desc_links(const uint8_t *data, int32_t len) {
static constexpr size_t MAX_DMA_LEN = (4096-4);
}
// ===== ESP32-S3 Pin Control =====
void uDisplay::cs_control(bool level) {
auto pin = par_cs;
if (pin < 0) return;
if (level) {
gpio_hi(pin);
}
else {
gpio_lo(pin);
}
}
void uDisplay::_pb_init_pin(bool read) {
if (read) {
if (interface == _UDSP_PAR8) {
for (size_t i = 0; i < 8; ++i) {
gpio_ll_output_disable(&GPIO, (gpio_num_t)par_dbl[i]);
}
} else {
for (size_t i = 0; i < 8; ++i) {
gpio_ll_output_disable(&GPIO, (gpio_num_t)par_dbl[i]);
}
for (size_t i = 0; i < 8; ++i) {
gpio_ll_output_disable(&GPIO, (gpio_num_t)par_dbh[i]);
}
}
}
else {
auto idx_base = LCD_DATA_OUT0_IDX;
if (interface == _UDSP_PAR8) {
for (size_t i = 0; i < 8; ++i) {
gpio_matrix_out(par_dbl[i], idx_base + i, 0, 0);
}
} else {
for (size_t i = 0; i < 8; ++i) {
gpio_matrix_out(par_dbl[i], idx_base + i, 0, 0);
}
for (size_t i = 0; i < 8; ++i) {
gpio_matrix_out(par_dbh[i], idx_base + 8 + i, 0, 0);
}
}
}
}
// ===== ESP32-S3 Simple Resistive Touch =====
uint32_t uDisplay::get_sr_touch(uint32_t _xp, uint32_t _xm, uint32_t _yp, uint32_t _ym) {
uint32_t aval = 0;
uint16_t xp,yp;
if (pb_busy()) return 0;
_pb_init_pin(true);
gpio_matrix_out(par_rs, 0x100, 0, 0);
pinMode(_ym, INPUT_PULLUP); // d0
pinMode(_yp, INPUT_PULLUP); // rs
pinMode(_xm, OUTPUT); // cs
pinMode(_xp, OUTPUT); // d1
digitalWrite(_xm, HIGH); // cs
digitalWrite(_xp, LOW); // d1
xp = 4096 - analogRead(_ym); // d0
pinMode(_xm, INPUT_PULLUP); // cs
pinMode(_xp, INPUT_PULLUP); // d1
pinMode(_ym, OUTPUT); // d0
pinMode(_yp, OUTPUT); // rs
digitalWrite(_ym, HIGH); // d0
digitalWrite(_yp, LOW); // rs
yp = 4096 - analogRead(_xp); // d1
aval = (xp << 16) | yp;
pinMode(_yp, OUTPUT); // rs
pinMode(_xm, OUTPUT); // cs
pinMode(_ym, OUTPUT); // d0
pinMode(_xp, OUTPUT); // d1
digitalWrite(_yp, HIGH); // rs
digitalWrite(_xm, HIGH); // cs
_pb_init_pin(false);
gpio_matrix_out(par_rs, LCD_DC_IDX, 0, 0);
return aval;
}
#endif // USE_ESP32_S3

View File

@ -0,0 +1,565 @@
#include "uDisplay.h"
#include "uDisplay_config.h"
#include "uDisplay_spi.h"
// ===== Basic Drawing Primitives =====
static constexpr uint16_t RGB16_TO_MONO = 0x8410;
static constexpr uint16_t RGB16_SWAP_TO_MONO = 0x1084;
#define renderer_swap(a, b) { int16_t t = a; a = b; b = t; }
void uDisplay::drawPixel(int16_t x, int16_t y, uint16_t color) {
#ifdef USE_ESP32_S3
if (interface == _UDSP_RGB) {
drawPixel_RGB(x, y, color);
return;
}
#endif
if (ep_mode) {
drawPixel_EPD(x, y, color);
return;
}
if (framebuffer) {
Renderer::drawPixel(x, y, color);
return;
}
if ((x < 0) || (x >= _width) || (y < 0) || (y >= _height)) return;
SPI_BEGIN_TRANSACTION
SPI_CS_LOW
setAddrWindow_int(x, y, 1, 1);
WriteColor(color);
SPI_CS_HIGH
SPI_END_TRANSACTION
}
void uDisplay::drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color) {
if (ep_mode) {
drawFastHLine_EPD(x, y, w, color);
return;
}
if (framebuffer) {
Renderer::drawFastHLine(x, y, w, color);
return;
}
// Rudimentary clipping
if((x >= _width) || (y >= _height)) return;
if((x + w - 1) >= _width) w = _width - x;
#ifdef USE_ESP32_S3
if (interface == _UDSP_RGB) {
if (cur_rot > 0) {
while (w--) {
drawPixel_RGB(x , y , color);
x++;
}
} else {
uint16_t *fb = rgb_fb;
fb += (int32_t)y * _width;
fb += x;
while (w--) {
*fb = color;
Cache_WriteBack_Addr((uint32_t)fb, 2);
fb++;
x++;
}
}
return;
}
#endif
SPI_BEGIN_TRANSACTION
SPI_CS_LOW
setAddrWindow_int(x, y, w, 1);
if (col_mode == 18) {
uint8_t r = (color & 0xF800) >> 11;
uint8_t g = (color & 0x07E0) >> 5;
uint8_t b = color & 0x001F;
r = (r * 255) / 31;
g = (g * 255) / 63;
b = (b * 255) / 31;
while (w--) {
ulcd_data8(r);
ulcd_data8(g);
ulcd_data8(b);
}
} else {
while (w--) {
WriteColor(color);
}
}
SPI_CS_HIGH
SPI_END_TRANSACTION
}
void uDisplay::drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color) {
if (ep_mode) {
drawFastVLine_EPD(x, y, h, color);
return;
}
if (framebuffer) {
Renderer::drawFastVLine(x, y, h, color);
return;
}
// Rudimentary clipping
if ((x >= _width) || (y >= _height)) return;
if ((y + h - 1) >= _height) h = _height - y;
#ifdef USE_ESP32_S3
if (interface == _UDSP_RGB) {
if (cur_rot > 0) {
while (h--) {
drawPixel_RGB(x , y , color);
y++;
}
} else {
uint16_t *fb = rgb_fb;
fb += (int32_t)y * _width;
fb += x;
while (h--) {
*fb = color;
Cache_WriteBack_Addr((uint32_t)fb, 2);
fb+=_width;
y++;
}
}
return;
}
#endif
SPI_BEGIN_TRANSACTION
SPI_CS_LOW
setAddrWindow_int(x, y, 1, h);
if (col_mode == 18) {
uint8_t r = (color & 0xF800) >> 11;
uint8_t g = (color & 0x07E0) >> 5;
uint8_t b = color & 0x001F;
r = (r * 255) / 31;
g = (g * 255) / 63;
b = (b * 255) / 31;
while (h--) {
ulcd_data8(r);
ulcd_data8(g);
ulcd_data8(b);
}
} else {
while (h--) {
WriteColor(color);
}
}
SPI_CS_HIGH
SPI_END_TRANSACTION
}
void uDisplay::fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color) {
#ifdef USE_ESP32_S3
if (interface == _UDSP_RGB) {
for (uint32_t yp = y; yp < y + h; yp++) {
drawFastHLine(x, yp, w, color);
}
return;
}
#endif
if (ep_mode) {
fillRect_EPD(x, y, w, h, color);
return;
}
if (framebuffer) {
Renderer::fillRect(x, y, w, h, color);
return;
}
if((x >= _width) || (y >= _height)) return;
if((x + w - 1) >= _width) w = _width - x;
if((y + h - 1) >= _height) h = _height - y;
SPI_BEGIN_TRANSACTION
SPI_CS_LOW
setAddrWindow_int(x, y, w, h);
if (col_mode == 18) {
uint8_t r = (color & 0xF800) >> 11;
uint8_t g = (color & 0x07E0) >> 5;
uint8_t b = color & 0x001F;
r = (r * 255) / 31;
g = (g * 255) / 63;
b = (b * 255) / 31;
for (y = h; y > 0; y--) {
for (x = w; x > 0; x--) {
ulcd_data8(r);
ulcd_data8(g);
ulcd_data8(b);
}
}
} else {
for (y = h; y > 0; y--) {
for (x = w; x > 0; x--) {
WriteColor(color);
}
}
}
SPI_CS_HIGH
SPI_END_TRANSACTION
}
void uDisplay::fillScreen(uint16_t color) {
fillRect(0, 0, width(), height(), color);
}
static inline void lvgl_color_swap(uint16_t *data, uint16_t len) { for (uint32_t i = 0; i < len; i++) (data[i] = data[i] << 8 | data[i] >> 8); }
void uDisplay::pushColors(uint16_t *data, uint16_t len, boolean not_swapped) {
if (lvgl_param.swap_color) {
not_swapped = !not_swapped;
}
//Serial.printf("push %x - %d - %d - %d\n", (uint32_t)data, len, not_swapped, lvgl_param.data);
// Isolating _UDSP_RGB to increase code sharing
//
// Use ESP-IDF LCD driver to push colors and rely on the following assumptions:
// * bytes swapping is already handled in the driver configuration (see uDisplay::Init()),
// * pushColors() is only called with not_swapped equals true,
// * cache flushing is done by the LCD driver.
if (interface == _UDSP_RGB) {
#ifdef USE_ESP32_S3
if (!not_swapped) {
// internal error -> write error message but continue (with possibly wrong colors)
AddLog(LOG_LEVEL_ERROR, PSTR("DSP: Unexpected byte-swapping requested in pushColors()"));
}
// check that bytes count matches the size of area, and remove from inner loop
if ((seta_yp2 - seta_yp1) * (seta_xp2 - seta_xp2) > len) { return; }
esp_lcd_panel_draw_bitmap(_panel_handle, seta_xp1, seta_yp1, seta_xp2, seta_yp2, (void *)data);
#endif
return;
}
if (not_swapped == false) {
// called from LVGL bytes are swapped
if (bpp != 16) {
// lvgl_color_swap(data, len); -- no need to swap anymore, we have inverted the mask
pushColorsMono(data, len, true);
return;
}
if ( (col_mode != 18) && (spi_dc >= 0) && (spi_nr <= 2) ) {
// special version 8 bit spi I or II
#ifdef ESP8266
lvgl_color_swap(data, len);
while (len--) {
uspi->write(*data++);
}
#else
if (lvgl_param.use_dma) {
pushPixelsDMA(data, len );
} else {
uspi->writeBytes((uint8_t*)data, len * 2);
}
#endif
} else {
#ifdef ESP32
if ( (col_mode == 18) && (spi_dc >= 0) && (spi_nr <= 2) ) {
uint8_t *line = (uint8_t*)malloc(len * 3);
uint8_t *lp = line;
if (line) {
uint16_t color;
for (uint32_t cnt = 0; cnt < len; cnt++) {
color = *data++;
color = (color << 8) | (color >> 8);
uint8_t r = (color & 0xF800) >> 11;
uint8_t g = (color & 0x07E0) >> 5;
uint8_t b = color & 0x001F;
r = (r * 255) / 31;
g = (g * 255) / 63;
b = (b * 255) / 31;
*lp++ = r;
*lp++ = g;
*lp++ = b;
}
if (lvgl_param.use_dma) {
pushPixels3DMA(line, len );
} else {
uspi->writeBytes(line, len * 3);
}
free(line);
}
} else {
// 9 bit and others
if (interface == _UDSP_PAR8 || interface == _UDSP_PAR16) {
#ifdef USE_ESP32_S3
pb_pushPixels(data, len, true, false);
#endif // USE_ESP32_S3
} else {
lvgl_color_swap(data, len);
while (len--) {
WriteColor(*data++);
}
}
}
#endif // ESP32
#ifdef ESP8266
lvgl_color_swap(data, len);
while (len--) {
WriteColor(*data++);
}
#endif
}
} else {
// called from displaytext, no byte swap, currently no dma here
if (bpp != 16) {
pushColorsMono(data, len);
return;
}
if ( (col_mode != 18) && (spi_dc >= 0) && (spi_nr <= 2) ) {
// special version 8 bit spi I or II
#ifdef ESP8266
while (len--) {
//uspi->write(*data++);
WriteColor(*data++);
}
#else
uspi->writePixels(data, len * 2);
#endif
} else {
// 9 bit and others
if (interface == _UDSP_PAR8 || interface == _UDSP_PAR16) {
#ifdef USE_ESP32_S3
pb_pushPixels(data, len, false, false);
#endif // USE_ESP32_S3
} else {
while (len--) {
WriteColor(*data++);
}
}
}
}
}
// convert to mono, these are framebuffer based
void uDisplay::pushColorsMono(uint16_t *data, uint16_t len, bool rgb16_swap) {
// pixel is white if at least one of the 3 components is above 50%
// this is tested with a simple mask, swapped if needed
uint16_t rgb16_to_mono_mask = rgb16_swap ? RGB16_SWAP_TO_MONO : RGB16_TO_MONO;
for (uint32_t y = seta_yp1; y < seta_yp2; y++) {
seta_yp1++;
if (lvgl_param.invert_bw) {
for (uint32_t x = seta_xp1; x < seta_xp2; x++) {
uint16_t color = *data++;
if (bpp == 1) color = (color & rgb16_to_mono_mask) ? 0 : 1;
drawPixel(x, y, color); // todo - inline the method to save speed
len--;
if (!len) return; // failsafe - exist if len (pixel number) is exhausted
}
} else {
for (uint32_t x = seta_xp1; x < seta_xp2; x++) {
uint16_t color = *data++;
if (bpp == 1) color = (color & rgb16_to_mono_mask) ? 1 : 0;
drawPixel(x, y, color); // todo - inline the method to save speed
len--;
if (!len) return; // failsafe - exist if len (pixel number) is exhausted
}
}
}
}
void uDisplay::setAddrWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) {
if (bpp != 16 || interface == _UDSP_RGB) {
// Just save params or update frame
if (!x0 && !y0 && !x1 && !y1) {
if (!ep_mode) {
Updateframe();
}
} else {
seta_xp1 = x0;
seta_xp2 = x1;
seta_yp1 = y0;
seta_yp2 = y1;
}
return;
}
if (interface == _UDSP_RGB) {
return;
}
if (!x0 && !y0 && !x1 && !y1) {
SPI_CS_HIGH
SPI_END_TRANSACTION
} else {
SPI_BEGIN_TRANSACTION
SPI_CS_LOW
setAddrWindow_int(x0, y0, x1 - x0, y1 - y0);
}
}
void uDisplay::setAddrWindow_int(uint16_t x, uint16_t y, uint16_t w, uint16_t h) {
if (interface == _UDSP_RGB) {
return;
}
x += x_addr_offs[cur_rot];
y += y_addr_offs[cur_rot];
if (sa_mode != 8) {
uint32_t xa = ((uint32_t)x << 16) | (x + w - 1);
uint32_t ya = ((uint32_t)y << 16) | (y + h - 1);
ulcd_command(saw_1);
ulcd_data32(xa);
ulcd_command(saw_2);
ulcd_data32(ya);
if (saw_3 != 0xff) {
ulcd_command(saw_3); // write to RAM
}
} else {
uint16_t x2 = x + w - 1,
y2 = y + h - 1;
if (cur_rot & 1) { // Vertical address increment mode
renderer_swap(x,y);
renderer_swap(x2,y2);
}
ulcd_command(saw_1);
if (allcmd_mode) {
ulcd_data8(x);
ulcd_data8(x2);
} else {
ulcd_command(x);
ulcd_command(x2);
}
ulcd_command(saw_2);
if (allcmd_mode) {
ulcd_data8(y);
ulcd_data8(y2);
} else {
ulcd_command(y);
ulcd_command(y2);
}
if (saw_3 != 0xff) {
ulcd_command(saw_3); // write to RAM
}
}
}
void uDisplay::setRotation(uint8_t rotation) {
cur_rot = rotation;
if (framebuffer) {
Renderer::setRotation(cur_rot);
return;
}
if (interface == _UDSP_SPI || interface == _UDSP_PAR8 || interface == _UDSP_PAR16) {
if (ep_mode) {
Renderer::setRotation(cur_rot);
return;
}
SPI_BEGIN_TRANSACTION
SPI_CS_LOW
ulcd_command(madctrl);
if (!allcmd_mode) {
ulcd_data8(rot[cur_rot]);
} else {
ulcd_command(rot[cur_rot]);
}
if ((sa_mode == 8) && !allcmd_mode) {
ulcd_command(startline);
ulcd_data8((cur_rot < 2) ? height() : 0);
}
SPI_CS_HIGH
SPI_END_TRANSACTION
}
switch (rotation) {
case 0:
_width = gxs;
_height = gys;
break;
case 1:
_width = gys;
_height = gxs;
break;
case 2:
_width = gxs;
_height = gys;
break;
case 3:
_width = gys;
_height = gxs;
break;
}
#ifdef USE_ESP32_S3
if (interface == _UDSP_RGB) {
// Utilize the ESP-IDF LCD driver's support for display rotation
esp_lcd_panel_mirror(_panel_handle, rotation == 1 || rotation == 2, rotation & 2);
esp_lcd_panel_swap_xy(_panel_handle, rotation & 1);
}
#endif
}
#ifdef USE_ESP32_S3
void uDisplay::drawPixel_RGB(int16_t x, int16_t y, uint16_t color) {
int16_t w = _width, h = _height;
if ((x < 0) || (x >= w) || (y < 0) || (y >= h)) {
return;
}
// check rotation, move pixel around if necessary
switch (cur_rot) {
case 1:
renderer_swap(w, h);
renderer_swap(x, y);
x = w - x - 1;
break;
case 2:
x = w - x - 1;
y = h - y - 1;
break;
case 3:
renderer_swap(w, h);
renderer_swap(x, y);
y = h - y - 1;
break;
}
uint16_t *fb = rgb_fb;
fb += (int32_t)y * w;
fb += x;
*fb = color;
Cache_WriteBack_Addr((uint32_t)fb, 2);
}
#endif

View File

@ -0,0 +1,142 @@
#include "uDisplay.h"
#include "uDisplay_config.h"
#ifdef USE_ESP32_S3
#ifdef ESP32
#include "esp8266toEsp32.h"
#endif
#define WAIT_LCD_NOT_BUSY while (*reg_lcd_user & LCD_CAM_LCD_START) {}
// ===== Parallel Bus Control Functions =====
void uDisplay::pb_beginTransaction(void) {
auto dev = _dev;
dev->lcd_clock.val = _clock_reg_value;
dev->lcd_misc.val = LCD_CAM_LCD_CD_IDLE_EDGE;
dev->lcd_user.val = LCD_CAM_LCD_CMD | LCD_CAM_LCD_UPDATE_REG;
_cache_flip = _cache[0];
}
void uDisplay::pb_endTransaction(void) {
auto dev = _dev;
while (dev->lcd_user.val & LCD_CAM_LCD_START) {}
}
void uDisplay::pb_wait(void) {
auto dev = _dev;
while (dev->lcd_user.val & LCD_CAM_LCD_START) {}
}
bool uDisplay::pb_busy(void) {
auto dev = _dev;
return (dev->lcd_user.val & LCD_CAM_LCD_START);
}
// ===== Parallel Bus Write Functions =====
bool uDisplay::pb_writeCommand(uint32_t data, uint_fast8_t bit_length) {
auto dev = _dev;
auto reg_lcd_user = &(dev->lcd_user.val);
dev->lcd_misc.val = LCD_CAM_LCD_CD_IDLE_EDGE | LCD_CAM_LCD_CD_CMD_SET;
if (interface == _UDSP_PAR8) {
auto bytes = bit_length >> 3;
do {
dev->lcd_cmd_val.lcd_cmd_value = data;
data >>= 8;
WAIT_LCD_NOT_BUSY
*reg_lcd_user = LCD_CAM_LCD_CMD | LCD_CAM_LCD_UPDATE_REG | LCD_CAM_LCD_START;
} while (--bytes);
return true;
} else {
dev->lcd_cmd_val.val = data;
WAIT_LCD_NOT_BUSY
*reg_lcd_user = LCD_CAM_LCD_2BYTE_EN | LCD_CAM_LCD_CMD | LCD_CAM_LCD_UPDATE_REG | LCD_CAM_LCD_START;
return true;
}
}
void uDisplay::pb_writeData(uint32_t data, uint_fast8_t bit_length) {
auto dev = _dev;
auto reg_lcd_user = &(dev->lcd_user.val);
dev->lcd_misc.val = LCD_CAM_LCD_CD_IDLE_EDGE;
auto bytes = bit_length >> 3;
if (interface == _UDSP_PAR8) {
uint8_t shift = (bytes - 1) * 8;
for (uint32_t cnt = 0; cnt < bytes; cnt++) {
dev->lcd_cmd_val.lcd_cmd_value = (data >> shift) & 0xff;
shift -= 8;
WAIT_LCD_NOT_BUSY
*reg_lcd_user = LCD_CAM_LCD_CMD | LCD_CAM_LCD_UPDATE_REG | LCD_CAM_LCD_START;
}
return;
} else {
if (bytes == 1 || bytes == 4) {
uint8_t shift = (bytes - 1) * 8;
for (uint32_t cnt = 0; cnt < bytes; cnt++) {
dev->lcd_cmd_val.lcd_cmd_value = (data >> shift) & 0xff;
shift -= 8;
WAIT_LCD_NOT_BUSY
*reg_lcd_user = LCD_CAM_LCD_2BYTE_EN | LCD_CAM_LCD_CMD | LCD_CAM_LCD_UPDATE_REG | LCD_CAM_LCD_START;
}
return;
}
dev->lcd_cmd_val.val = data;
WAIT_LCD_NOT_BUSY
*reg_lcd_user = LCD_CAM_LCD_2BYTE_EN | LCD_CAM_LCD_CMD | LCD_CAM_LCD_UPDATE_REG | LCD_CAM_LCD_START;
return;
}
}
void uDisplay::pb_pushPixels(uint16_t* data, uint32_t length, bool swap_bytes, bool use_dma) {
auto dev = _dev;
auto reg_lcd_user = &(dev->lcd_user.val);
dev->lcd_misc.val = LCD_CAM_LCD_CD_IDLE_EDGE;
if (interface == _UDSP_PAR8) {
if (swap_bytes) {
for (uint32_t cnt = 0; cnt < length; cnt++) {
dev->lcd_cmd_val.lcd_cmd_value = *data;
while (*reg_lcd_user & LCD_CAM_LCD_START) {}
*reg_lcd_user = LCD_CAM_LCD_CMD | LCD_CAM_LCD_UPDATE_REG | LCD_CAM_LCD_START;
dev->lcd_cmd_val.lcd_cmd_value = *data >> 8;
WAIT_LCD_NOT_BUSY
*reg_lcd_user = LCD_CAM_LCD_CMD | LCD_CAM_LCD_UPDATE_REG | LCD_CAM_LCD_START;
data++;
}
} else {
for (uint32_t cnt = 0; cnt < length; cnt++) {
dev->lcd_cmd_val.lcd_cmd_value = *data >> 8;
while (*reg_lcd_user & LCD_CAM_LCD_START) {}
*reg_lcd_user = LCD_CAM_LCD_CMD | LCD_CAM_LCD_UPDATE_REG | LCD_CAM_LCD_START;
dev->lcd_cmd_val.lcd_cmd_value = *data;
WAIT_LCD_NOT_BUSY
*reg_lcd_user = LCD_CAM_LCD_CMD | LCD_CAM_LCD_UPDATE_REG | LCD_CAM_LCD_START;
data++;
}
}
} else {
if (swap_bytes) {
uint16_t iob;
for (uint32_t cnt = 0; cnt < length; cnt++) {
iob = *data++;
iob = (iob << 8) | (iob >> 8);
dev->lcd_cmd_val.lcd_cmd_value = iob;
WAIT_LCD_NOT_BUSY
*reg_lcd_user = LCD_CAM_LCD_2BYTE_EN | LCD_CAM_LCD_CMD | LCD_CAM_LCD_UPDATE_REG | LCD_CAM_LCD_START;
}
} else {
for (uint32_t cnt = 0; cnt < length; cnt++) {
dev->lcd_cmd_val.lcd_cmd_value = *data++;
WAIT_LCD_NOT_BUSY
*reg_lcd_user = LCD_CAM_LCD_2BYTE_EN | LCD_CAM_LCD_CMD | LCD_CAM_LCD_UPDATE_REG | LCD_CAM_LCD_START;
}
}
}
}
#endif

View File

@ -0,0 +1,154 @@
#include "uDisplay.h"
#include "uDisplay_config.h"
#include "uDisplay_spi.h"
#ifndef ESP32
#include "spi_register.h"
#endif
// ===== Low-Level SPI Write Functions =====
// ===== RA8876 Controller Commands =====
static constexpr uint8_t RA8876_DATA_WRITE = 0x80;
static constexpr uint8_t RA8876_DATA_READ = 0xC0;
static constexpr uint8_t RA8876_CMD_WRITE = 0x00;
static constexpr uint8_t RA8876_STATUS_READ = 0x40;
#ifdef ESP32
void uDisplay::hw_write9(uint8_t val, uint8_t dc) {
if (spi_dc < -1) {
// RA8876 mode
if (!dc) {
uspi->write(RA8876_CMD_WRITE);
uspi->write(val);
} else {
uspi->write(RA8876_DATA_WRITE);
uspi->write(val);
}
} else {
uint32_t regvalue = val >> 1;
if (dc) regvalue |= 0x80;
else regvalue &= 0x7f;
if (val & 1) regvalue |= 0x8000;
REG_SET_BIT(SPI_USER_REG(3), SPI_USR_MOSI);
REG_WRITE(SPI_MOSI_DLEN_REG(3), 9 - 1);
uint32_t *dp = (uint32_t*)SPI_W0_REG(3);
*dp = regvalue;
REG_SET_BIT(SPI_CMD_REG(3), SPI_USR);
while (REG_GET_FIELD(SPI_CMD_REG(3), SPI_USR));
}
}
#else
void uDisplay::hw_write9(uint8_t val, uint8_t dc) {
if (spi_dc < -1) {
// RA8876 mode
if (!dc) {
uspi->write(RA8876_CMD_WRITE);
uspi->write(val);
} else {
uspi->write(RA8876_DATA_WRITE);
uspi->write(val);
}
} else {
uint32_t regvalue;
uint8_t bytetemp;
if (!dc) {
bytetemp = (val>> 1) & 0x7f;
} else {
bytetemp = (val >> 1) | 0x80;
}
regvalue = ((8 & SPI_USR_COMMAND_BITLEN) << SPI_USR_COMMAND_BITLEN_S) | ((uint32)bytetemp);
if (val & 0x01) regvalue |= BIT15;
while (READ_PERI_REG(SPI_CMD(1)) & SPI_USR);
WRITE_PERI_REG(SPI_USER2(1), regvalue);
SET_PERI_REG_MASK(SPI_CMD(1), SPI_USR);
}
}
#endif
// ===== Software SPI (Slow) Functions =====
void uDisplay::write8(uint8_t val) {
for (uint8_t bit = 0x80; bit; bit >>= 1) {
GPIO_CLR(spi_clk);
if (val & bit) GPIO_SET(spi_mosi);
else GPIO_CLR(spi_mosi);
GPIO_SET(spi_clk);
}
}
void uDisplay::write8_slow(uint8_t val) {
for (uint8_t bit = 0x80; bit; bit >>= 1) {
GPIO_CLR_SLOW(spi_clk);
if (val & bit) GPIO_SET_SLOW(spi_mosi);
else GPIO_CLR_SLOW(spi_mosi);
GPIO_SET_SLOW(spi_clk);
}
}
void uDisplay::write9(uint8_t val, uint8_t dc) {
GPIO_CLR(spi_clk);
if (dc) GPIO_SET(spi_mosi);
else GPIO_CLR(spi_mosi);
GPIO_SET(spi_clk);
for (uint8_t bit = 0x80; bit; bit >>= 1) {
GPIO_CLR(spi_clk);
if (val & bit) GPIO_SET(spi_mosi);
else GPIO_CLR(spi_mosi);
GPIO_SET(spi_clk);
}
}
void uDisplay::write9_slow(uint8_t val, uint8_t dc) {
GPIO_CLR_SLOW(spi_clk);
if (dc) GPIO_SET_SLOW(spi_mosi);
else GPIO_CLR_SLOW(spi_mosi);
GPIO_SET_SLOW(spi_clk);
for (uint8_t bit = 0x80; bit; bit >>= 1) {
GPIO_CLR_SLOW(spi_clk);
if (val & bit) GPIO_SET_SLOW(spi_mosi);
else GPIO_CLR_SLOW(spi_mosi);
GPIO_SET_SLOW(spi_clk);
}
}
void uDisplay::write16(uint16_t val) {
for (uint16_t bit = 0x8000; bit; bit >>= 1) {
GPIO_CLR(spi_clk);
if (val & bit) GPIO_SET(spi_mosi);
else GPIO_CLR(spi_mosi);
GPIO_SET(spi_clk);
}
}
void uDisplay::write32(uint32_t val) {
for (uint32_t bit = 0x80000000; bit; bit >>= 1) {
GPIO_CLR(spi_clk);
if (val & bit) GPIO_SET(spi_mosi);
else GPIO_CLR(spi_mosi);
GPIO_SET(spi_clk);
}
}
// ===== RA8876 Specific Functions =====
uint8_t uDisplay::writeReg16(uint8_t reg, uint16_t wval) {
hw_write9(reg, 0);
hw_write9(wval, 1);
hw_write9(reg + 1, 0);
hw_write9(wval >> 8, 1);
return 0;
}
uint8_t uDisplay::readData(void) {
uspi->write(RA8876_DATA_READ);
uint8_t val = uspi->transfer(0);
return val;
}
uint8_t uDisplay::readStatus(void) {
uspi->write(RA8876_STATUS_READ);
uint8_t val = uspi->transfer(0);
return val;
}

View File

@ -0,0 +1,71 @@
#ifndef UDISPLAY_SPI_LOWLEVEL_H
#define UDISPLAY_SPI_LOWLEVEL_H
#include "uDisplay_config.h"
// ===== SPI Platform-Specific Includes =====
#ifdef ESP32
#include "soc/spi_reg.h"
#include "soc/spi_struct.h"
#include "esp32-hal-spi.h"
#include "esp32-hal.h"
#include "soc/spi_struct.h"
#endif
// ===== GPIO Control Macros =====
#ifdef ESP8266
#define PIN_OUT_SET 0x60000304
#define PIN_OUT_CLEAR 0x60000308
#define GPIO_SET(A) WRITE_PERI_REG( PIN_OUT_SET, 1 << A)
#define GPIO_CLR(A) WRITE_PERI_REG( PIN_OUT_CLEAR, 1 << A)
#define GPIO_CLR_SLOW(A) digitalWrite(A, LOW)
#define GPIO_SET_SLOW(A) digitalWrite(A, HIGH)
#else // ESP32
#undef GPIO_SET
#undef GPIO_CLR
#undef GPIO_SET_SLOW
#undef GPIO_CLR_SLOW
#if CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C5 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32P4
#define GPIO_CLR(A) GPIO.out_w1tc.val = (1 << A)
#define GPIO_SET(A) GPIO.out_w1ts.val = (1 << A)
#else // plain ESP32
#define GPIO_CLR(A) GPIO.out_w1tc = (1 << A)
#define GPIO_SET(A) GPIO.out_w1ts = (1 << A)
#endif
#define GPIO_CLR_SLOW(A) digitalWrite(A, LOW)
#define GPIO_SET_SLOW(A) digitalWrite(A, HIGH)
#endif
// ===== SPI Transaction Control Macros =====
#define SPI_BEGIN_TRANSACTION if (spi_nr <= 2) beginTransaction(spiSettings);
#define SPI_END_TRANSACTION if (spi_nr <= 2) endTransaction();
#define SPI_CS_LOW if (spi_cs >= 0) GPIO_CLR_SLOW(spi_cs);
#define SPI_CS_HIGH if (spi_cs >= 0) GPIO_SET_SLOW(spi_cs);
#define SPI_DC_LOW if (spi_dc >= 0) GPIO_CLR_SLOW(spi_dc);
#define SPI_DC_HIGH if (spi_dc >= 0) GPIO_SET_SLOW(spi_dc);
// ===== Function Declarations =====
// These would typically be in the class declaration in uDisplay.h
// but we list them here for reference:
/*
// Low-Level SPI Write Functions
void hw_write9(uint8_t val, uint8_t dc);
void write8(uint8_t val);
void write8_slow(uint8_t val);
void write9(uint8_t val, uint8_t dc);
void write9_slow(uint8_t val, uint8_t dc);
void write16(uint16_t val);
void write32(uint32_t val);
// RA8876 Specific Functions
uint8_t writeReg16(uint8_t reg, uint16_t wval);
uint8_t readData(void);
uint8_t readStatus(void);
*/
#endif // UDISPLAY_SPI_LOWLEVEL_H

View File

@ -0,0 +1,158 @@
#include "uDisplay.h"
#include "uDisplay_config.h"
#include "uDisplay_spi.h" // Your SPI header
// ===== High-Level SPI Communication Functions =====
void uDisplay::ulcd_command(uint8_t val) {
if (interface == _UDSP_SPI) {
if (spi_dc < 0) {
if (spi_nr > 2) {
if (spi_nr == 3) {
write9(val, 0);
} else {
write9_slow(val, 0);
}
} else {
hw_write9(val, 0);
}
} else {
SPI_DC_LOW
if (spi_nr > 2) {
if (spi_nr == 3) {
write8(val);
} else {
write8_slow(val);
}
} else {
uspi->write(val);
}
SPI_DC_HIGH
}
return;
}
#ifdef USE_ESP32_S3
if (interface == _UDSP_PAR8 || interface == _UDSP_PAR16) {
pb_writeCommand(val, 8);
}
#endif
}
void uDisplay::ulcd_data8(uint8_t val) {
if (interface == _UDSP_SPI) {
if (spi_dc < 0) {
if (spi_nr > 2) {
if (spi_nr == 3) {
write9(val, 1);
} else {
write9_slow(val, 1);
}
} else {
hw_write9(val, 1);
}
} else {
if (spi_nr > 2) {
if (spi_nr == 3) {
write8(val);
} else {
write8_slow(val);
}
} else {
uspi->write(val);
}
}
return;
}
#ifdef USE_ESP32_S3
if (interface == _UDSP_PAR8 || interface == _UDSP_PAR16) {
pb_writeData(val, 8);
}
#endif
}
void uDisplay::ulcd_data16(uint16_t val) {
if (interface == _UDSP_SPI) {
if (spi_dc < 0) {
if (spi_nr > 2) {
write9(val >> 8, 1);
write9(val, 1);
} else {
hw_write9(val >> 8, 1);
hw_write9(val, 1);
}
} else {
if (spi_nr > 2) {
write16(val);
} else {
uspi->write16(val);
}
}
return;
}
#ifdef USE_ESP32_S3
if (interface == _UDSP_PAR8 || interface == _UDSP_PAR16) {
pb_writeData(val, 16);
}
#endif
}
void uDisplay::ulcd_data32(uint32_t val) {
if (interface == _UDSP_SPI) {
if (spi_dc < 0) {
if (spi_nr > 2) {
write9(val >> 24, 1);
write9(val >> 16, 1);
write9(val >> 8, 1);
write9(val, 1);
} else {
hw_write9(val >> 24, 1);
hw_write9(val >> 16, 1);
hw_write9(val >> 8, 1);
hw_write9(val, 1);
}
} else {
if (spi_nr > 2) {
write32(val);
} else {
uspi->write32(val);
}
}
return;
}
#ifdef USE_ESP32_S3
if (interface == _UDSP_PAR8 || interface == _UDSP_PAR16) {
pb_writeData(val, 32);
}
#endif
}
void uDisplay::ulcd_command_one(uint8_t val) {
if (interface == _UDSP_SPI) {
SPI_BEGIN_TRANSACTION
SPI_CS_LOW
ulcd_command(val);
SPI_CS_HIGH
SPI_END_TRANSACTION
}
}
void uDisplay::WriteColor(uint16_t color) {
if (col_mode == 18) {
uint8_t r = (color & 0xF800) >> 11;
uint8_t g = (color & 0x07E0) >> 5;
uint8_t b = color & 0x001F;
r = (r * 255) / 31;
g = (g * 255) / 63;
b = (b * 255) / 31;
ulcd_data8(r);
ulcd_data8(g);
ulcd_data8(b);
} else {
ulcd_data16(color);
}
}

View File

@ -0,0 +1,60 @@
#include "uDisplay.h"
#include "uDisplay_config.h"
// ===== Timing and Delay Functions =====
void uDisplay::delay_arg(uint32_t args) {
uint32_t delay_ms = 0;
switch (args & 0xE0) {
case 0x80: delay_ms = 150; break;
case 0xA0: delay_ms = 10; break;
case 0xE0: delay_ms = 500; break;
}
if (delay_ms > 0) {
delay(delay_ms);
AddLog(LOG_LEVEL_DEBUG, PSTR("DSP: delay %d ms"), delay_ms);
}
}
void uDisplay::reset_pin(int32_t msl, int32_t msh) {
if (reset > 0) {
digitalWrite(reset, LOW);
delay(msl);
digitalWrite(reset, HIGH);
delay(msh);
}
}
#define UDSP_BUSY_TIMEOUT 3000
void uDisplay::delay_sync(int32_t ms) {
uint8_t busy_level = HIGH;
if (lvgl_param.busy_invert) {
busy_level = LOW;
}
uint32_t time = millis();
if (busy_pin > 0) {
while (digitalRead(busy_pin) == busy_level) {
delay(1);
if ((millis() - time) > UDSP_BUSY_TIMEOUT) {
break;
}
}
} else {
delay(ms);
}
}
// ===== SPI Transaction Control =====
void uDisplay::beginTransaction(SPISettings s) {
#ifdef ESP32
if (lvgl_param.use_dma) {
dmaWait();
}
#endif
uspi->beginTransaction(s);
}
void uDisplay::endTransaction(void) {
uspi->endTransaction();
}

View File

@ -0,0 +1,568 @@
#include "uDisplay.h"
#include "uDisplay_config.h"
#ifdef USE_UNIVERSAL_TOUCH
// ===== Touch IRQ Handler =====
uint8_t ut_irq_flg;
void IRAM_ATTR ut_touch_irq(void) {
ut_irq_flg = 1;
}
// ===== Touch Initialization =====
bool uDisplay::utouch_Init(char **name) {
*name = ut_name;
if (ut_init_code) {
if (ut_reset >= 0) {
pinMode(ut_reset, OUTPUT);
digitalWrite(ut_reset, HIGH);
delay(10);
digitalWrite(ut_reset, LOW);
delay(5);
digitalWrite(ut_reset, HIGH);
delay(10);
}
if (ut_irq >= 0) {
pinMode(ut_irq, INPUT);
attachInterrupt(ut_irq, ut_touch_irq, FALLING);
}
if (ut_spi_nr == spi_nr) {
// same as display
ut_spi = uspi;
} else {
#ifdef ESP32
ut_spi = SpiBegin(ut_spi_nr);
#endif
}
return ut_execute(ut_init_code);
}
return false;
}
// ===== Touch Detection =====
uint16_t uDisplay::touched(void) {
if (ut_irq >= 0) {
if (!ut_irq_flg) {
return false;
}
ut_irq_flg = 0;
}
if (ut_touch_code) {
return ut_execute(ut_touch_code);
}
return 0;
}
// ===== Touch Coordinate Reading =====
int16_t uDisplay::getPoint_x(void) {
if (ut_getx_code) {
return ut_execute(ut_getx_code);
}
return 0;
}
int16_t uDisplay::getPoint_y(void) {
if (ut_gety_code) {
return ut_execute(ut_gety_code);
}
return 0;
}
// ===== Touch Command Execution =====
// ===== Touch Code Translation =====
void uDisplay::ut_trans(char **sp, uint8_t **code) {
char *cp = *sp;
uint16_t wval;
uint8_t tmp_code[64];
uint8_t *ut_code = tmp_code;
while (*cp) {
if (*cp == ':' || *cp == '#') {
break;
}
if (*cp == ';') {
// skip comment line
while (*cp) {
if (*cp == '\n') {
cp++;
break;
}
cp++;
}
}
if (!strncmp(cp, "RDWM", 4)) {
// read word many
*ut_code++ = UT_RDWM;
wval = ut_par(&cp, 0);
*ut_code++ = wval>>8;
*ut_code++ = wval;
wval = ut_par(&cp, 1);
if (wval > sizeof(ut_array)) {
wval = sizeof(ut_array);
}
*ut_code++ = wval;
} else if (!strncmp(cp, "RDW", 3)) {
// read word one
*ut_code++ = UT_RDW;
wval = ut_par(&cp, 0);
*ut_code++ = wval>>8;
*ut_code++ = wval;
} else if (!strncmp(cp, "RDM", 3)) {
// read many
*ut_code++ = UT_RDM;
*ut_code++ = ut_par(&cp, 0);
wval = ut_par(&cp, 1);
if (wval > sizeof(ut_array)) {
wval = sizeof(ut_array);
}
*ut_code++ = wval;
} else if (!strncmp(cp, "RD", 2)) {
// read one
*ut_code++ = UT_RD;
*ut_code++ = ut_par(&cp, 0);
} else if (!strncmp(cp, "CPR", 3)) {
// cmp and set
*ut_code++ = UT_CPR;
*ut_code++ = ut_par(&cp, 0);
} else if (!strncmp(cp, "CPM", 3)) {
// cmp multiple and set
*ut_code++ = UT_CPM;
uint8_t num = ut_par(&cp, 0);
*ut_code++ = num;
for (uint32_t cnt = 0; cnt < num; cnt++) {
*ut_code++ = ut_par(&cp, 0);
}
} else if (!strncmp(cp, "CP", 2)) {
// cmp and set
*ut_code++ = UT_CP;
*ut_code++ = ut_par(&cp, 0);
} else if (!strncmp(cp, "RTF", 3)) {
// return when false
*ut_code++ = UT_RTF;
} else if (!strncmp(cp, "RTT", 3)) {
// return when true
*ut_code++ = UT_RTT;
} else if (!strncmp(cp, "MVB", 3)) {
// move
*ut_code++ = UT_MVB;
*ut_code++ = ut_par(&cp, 1);
*ut_code++ = ut_par(&cp, 1);
} else if (!strncmp(cp, "MV", 2)) {
// move
*ut_code++ = UT_MV;
*ut_code++ = ut_par(&cp, 1);
*ut_code++ = ut_par(&cp, 1);
} else if (!strncmp(cp, "RT", 2)) {
// return status
*ut_code++ = UT_RT;
} else if (!strncmp(cp, "WRW", 3)) {
*ut_code++ = UT_WRW;
wval = ut_par(&cp, 0);
*ut_code++ = wval>>8;
*ut_code++ = wval;
wval = ut_par(&cp, 0);
*ut_code++ = wval;
} else if (!strncmp(cp, "WR", 2)) {
*ut_code++ = UT_WR;
wval = ut_par(&cp, 0);
*ut_code++ = wval;
wval = ut_par(&cp, 0);
*ut_code++ = wval;
} else if (!strncmp(cp, "AND", 3)) {
*ut_code++ = UT_AND;
wval = ut_par(&cp, 0);
*ut_code++ = wval >> 8;
*ut_code++ = wval;
} else if (!strncmp(cp, "SCL", 3)) {
*ut_code++ = UT_SCALE;
wval = ut_par(&cp, 1);
*ut_code++ = wval >> 8;
*ut_code++ = wval;
uint32_t lval = ut_par(&cp, 2);
*ut_code++ = lval >> 24;
*ut_code++ = lval >> 16;
*ut_code++ = lval >> 8;
*ut_code++ = lval;
} else if (!strncmp(cp, "LIM", 3)) {
*ut_code++ = UT_LIM;
wval = ut_par(&cp, 1);
*ut_code++ = wval >> 8;
*ut_code++ = wval;
} else if (!strncmp(cp, "GSRT", 4)) {
*ut_code++ = UT_GSRT;
wval = ut_par(&cp, 1);
*ut_code++ = wval >> 8;
*ut_code++ = wval;
} else if (!strncmp(cp, "XPT", 3)) {
*ut_code++ = UT_XPT;
wval = ut_par(&cp, 1);
*ut_code++ = wval >> 8;
*ut_code++ = wval;
} else if (!strncmp(cp, "DBG", 3)) {
*ut_code++ = UT_DBG;
wval = ut_par(&cp, 1);
*ut_code++ = wval;
}
cp++;
}
*ut_code++ = UT_END;
*sp = cp - 1;
uint16_t memsize = (uint32_t)ut_code - (uint32_t)tmp_code;
// allocate memory
uint8_t *mp = (uint8_t*)malloc(memsize + 2);
if (mp) {
memmove(mp, tmp_code, memsize);
*code = mp;
}
}
// ===== Touch Parameter Parsing =====
uint32_t uDisplay::ut_par(char **lp, uint32_t mode) {
char *cp = *lp;
while (*cp != ' ') {
if (!cp) break;
cp++;
}
cp++;
uint32_t result;
if (!mode) {
// hex
result = strtol(cp, &cp, 16);
} else if (mode == 1) {
// word
result = strtol(cp, &cp, 10);
} else {
// float as 32bit integer
float fval = CharToFloat(cp);
result = *(uint32_t*)&fval;
while (*cp) {
if (*cp == ' ' || *cp =='\n') {
break;
}
cp++;
}
}
*lp = cp;
return result;
}
int16_t uDisplay::ut_execute(uint8_t *ut_code) {
int16_t result = 0;
uint8_t iob, len;
uint16_t wval;
while (*ut_code != UT_END) {
iob = *ut_code++;
switch (iob) {
case UT_RD:
// read 1 byte
ut_code = ut_rd(ut_code, 1, 1);
break;
case UT_RDM:
// read multiple bytes
ut_code = ut_rd(ut_code, 2, 1);
break;
case UT_RDW:
// read 1 byte
ut_code = ut_rd(ut_code, 1, 2);
break;
case UT_RDWM:
// read multiple bytes
ut_code = ut_rd(ut_code, 2, 2);
break;
case UT_WR:
ut_code = ut_wr(ut_code, 1);
break;
case UT_WRW:
ut_code = ut_wr(ut_code, 2);
break;
case UT_CP:
// compare
iob = *ut_code++;
result = (iob == ut_array[0]);
break;
case UT_CPM:
// compare multiple
len = *ut_code++;
result = 0;
for (uint32_t cnt = 0; cnt < len; cnt++) {
iob = *ut_code++;
result |= (iob == ut_array[0]);
}
break;
case UT_CPR:
// compare
iob = *ut_code++;
result = (iob == result);
break;
case UT_RTF:
// return when false
if (result == 0) {
return false;
}
break;
case UT_RTT:
// return when true
if (result > 0) {
return false;
}
break;
case UT_MVB:
// move byte from index to high or low result
wval = *ut_code++;
iob = *ut_code++;
if (wval == 0) {
result &= 0xff00;
result |= ut_array[iob];
} else {
result &= 0x00ff;
result |= (ut_array[iob] << 8);
}
break;
case UT_MV:
// move
// source
result = *ut_code++;
iob = *ut_code++;
if (iob == 1) {
result = ut_array[result];
} else if (iob == 2) {
iob = result;
result = ut_array[iob] << 8;
result |= ut_array[iob + 1];
} else {
iob = result;
result = ut_array[iob + 1] << 8;
result |= ut_array[iob];
}
result &= 0xfff;
break;
case UT_AND:
// and
wval = *ut_code++ << 8;
wval |= *ut_code++;
result &= wval;
break;
case UT_SCALE:
{
wval = *ut_code++ << 8;
wval |= *ut_code++;
result -= wval;
uint32_t lval = (uint32_t)*ut_code++ << 24;
lval |= (uint32_t)*ut_code++ << 16;
lval |= (uint32_t)*ut_code++ << 8;
lval |= (uint32_t)*ut_code++;
float fval = *(float*)&lval;
fval *= (float)result;
result = fval;
}
break;
case UT_LIM:
wval = *ut_code++ << 8;
wval |= *ut_code++;
if (result > wval) {
result = wval;
}
break;
case UT_RT:
// result
return result;
break;
case UT_GSRT:
#ifdef USE_ESP32_S3
{
uint32_t val = get_sr_touch(SIMPLERS_XP, SIMPLERS_XM, SIMPLERS_YP, SIMPLERS_YM);
if (val == 0) {
return false;
}
uint16_t xp = val >> 16;
uint16_t yp = val;
wval = *ut_code++ << 8;
wval |= *ut_code++;
if (xp > wval && yp > wval) {
ut_array[0] = val >> 24;
ut_array[1] = val >> 16;
ut_array[2] = val >> 8;
ut_array[3] = val;
return true;
}
return false;
}
#endif // USE_ESP32_S3
break;
case UT_XPT:
wval = *ut_code++ << 8;
wval |= *ut_code++;
result = ut_XPT2046(wval);
break;
case UT_DBG:
// debug show result
wval = *ut_code++;
AddLog(LOG_LEVEL_INFO, PSTR("UTDBG %d: %02x : %02x,%02x,%02x,%02x"), wval, result, ut_array[0], ut_array[1], ut_array[2], ut_array[3]);
break;
case UT_END:
break;
}
}
return result;
}
// ===== Low-Level Touch Communication =====
uint8_t *uDisplay::ut_rd(uint8_t *iop, uint32_t len, uint32_t amode) {
if (ut_wire) {
// i2c mode
ut_wire->beginTransmission(ut_i2caddr);
ut_wire->write(*iop++);
if (amode == 2) {
ut_wire->write(*iop++);
}
ut_wire->endTransmission(false);
if (len > 1) {
len = *iop++;
}
ut_wire->requestFrom(ut_i2caddr, (size_t)len);
uint8_t index = 0;
while (ut_wire->available()) {
ut_array[index++] = ut_wire->read();
}
} else {
// spi mode
if (amode == 1) {
uint16_t val = *iop++;
uint16_t len = *iop++;
if (ut_spi) {
digitalWrite(ut_spi_cs, LOW);
ut_spi->beginTransaction(ut_spiSettings);
ut_spi->transfer(val);
val = ut_spi->transfer16(0);
ut_spi->endTransaction();
ut_array[len] = val << 8;
ut_array[len + 1] = val;
digitalWrite(ut_spi_cs, HIGH);
}
}
}
return iop;
}
uint8_t *uDisplay::ut_wr(uint8_t *iop, uint32_t amode) {
if (ut_wire) {
// i2c mode
ut_wire->beginTransmission(ut_i2caddr);
ut_wire->write(*iop++);
if (amode == 2) {
ut_wire->write(*iop++);
}
ut_wire->write(*iop++);
ut_wire->endTransmission(true);
} else {
// spi mode
}
return iop;
}
// ===== XPT2046 Touch Controller =====
uint16_t uDisplay::ut_XPT2046(uint16_t z_th) {
uint16_t result = 0;
if (ut_spi) {
int16_t data[6];
ut_spi->beginTransaction(ut_spiSettings);
digitalWrite(ut_spi_cs, LOW);
ut_spi->transfer(0xB1 /* Z1 */);
int16_t z1 = ut_spi->transfer16(0xC1 /* Z2 */) >> 3;
int16_t z = z1 + 4095;
int16_t z2 = ut_spi->transfer16(0x91 /* X */) >> 3;
z -= z2;
if (z >= z_th) {
ut_spi->transfer16(0x91 /* X */); // dummy X measure, 1st is always noisy
data[0] = ut_spi->transfer16(0xD1 /* Y */) >> 3;
data[1] = ut_spi->transfer16(0x91 /* X */) >> 3; // make 3 x-y measurements
data[2] = ut_spi->transfer16(0xD1 /* Y */) >> 3;
data[3] = ut_spi->transfer16(0x91 /* X */) >> 3;
result = 1;
} else {
data[0] = data[1] = data[2] = data[3] = 0;
}
data[4] = ut_spi->transfer16(0xD0 /* Y */) >> 3; // Last Y touch power down
data[5] = ut_spi->transfer16(0) >> 3;
digitalWrite(ut_spi_cs, HIGH);
ut_spi->endTransaction();
uint16_t x = besttwoavg(data[0], data[2], data[4]);
uint16_t y = besttwoavg(data[1], data[3], data[5]);
ut_array[0] = x >> 8;
ut_array[1] = x;
ut_array[2] = y >> 8;
ut_array[3] = y;
}
return result;
}
// ===== Touch Data Processing =====
int16_t uDisplay::besttwoavg(int16_t x, int16_t y, int16_t z) {
int16_t da, db, dc;
int16_t reta = 0;
if (x > y) da = x - y; else da = y - x;
if (x > z) db = x - z; else db = z - x;
if (z > y) dc = z - y; else dc = y - z;
if (da <= db && da <= dc) reta = (x + y) >> 1;
else if (db <= da && db <= dc) reta = (x + z) >> 1;
else reta = (y + z) >> 1;
return (reta);
}
#endif // USE_UNIVERSAL_TOUCH

View File

@ -0,0 +1,111 @@
#include "uDisplay.h"
#include "uDisplay_config.h"
// ===== String and Parsing Utilities =====
uint8_t uDisplay::strlen_ln(char *str) {
for (uint32_t cnt = 0; cnt < 256; cnt++) {
if (!str[cnt] || str[cnt] == '\n' || str[cnt] == ' ') return cnt;
}
return 0;
}
char *uDisplay::devname(void) {
return dname;
}
uint32_t uDisplay::str2c(char **sp, char *vp, uint32_t len) {
char *lp = *sp;
if (len) len--;
char *cp = strchr(lp, ',');
if (cp) {
while (1) {
if (*lp == ',') {
*vp = 0;
*sp = lp + 1;
return 0;
}
if (len) {
*vp++ = *lp++;
len--;
} else {
lp++;
}
}
} else {
uint16_t slen = strlen(lp);
if (slen) {
strlcpy(vp, *sp, len);
*sp = lp + slen;
return 0;
}
}
return 1;
}
int32_t uDisplay::next_val(char **sp) {
char ibuff[16];
if (!str2c(sp, ibuff, sizeof(ibuff))) {
return atoi(ibuff);
}
return 0xff;
}
uint32_t uDisplay::next_hex(char **sp) {
char ibuff[16];
if (!str2c(sp, ibuff, sizeof(ibuff))) {
return strtol(ibuff, 0, 16);
}
return 0xff;
}
// ===== Touch Coordinate Conversion =====
// the cases are PSEUDO_OPCODES from MODULE_DESCRIPTOR
// and may be expanded with more opcodes
void uDisplay::TS_RotConvert(int16_t *x, int16_t *y) {
int16_t temp;
if (rot_t[cur_rot] & 0x80) {
temp = *y;
*y = *x;
*x = temp;
}
if (rotmap_xmin >= 0) {
*y = map(*y, rotmap_ymin, rotmap_ymax, 0, gys);
*x = map(*x, rotmap_xmin, rotmap_xmax, 0, gxs);
*x = constrain(*x, 0, gxs);
*y = constrain(*y, 0, gys);
}
switch (rot_t[cur_rot] & 0xf) {
case 0:
break;
case 1:
temp = *y;
*y = height() - *x;
*x = temp;
break;
case 2:
*x = width() - *x;
*y = height() - *y;
break;
case 3:
temp = *y;
*y = *x;
*x = width() - temp;
break;
case 4:
*x = width() - *x;
break;
case 5:
*y = height() - *y;
break;
}
}
// ===== Color Conversion Helper =====
static inline void lvgl_color_swap(uint16_t *data, uint16_t len) {
for (uint32_t i = 0; i < len; i++) (data[i] = data[i] << 8 | data[i] >> 8);
}