Add rotation for RGB Panels

This commit is contained in:
fvanroie 2023-01-05 22:37:27 +01:00
parent 91ee270071
commit 6e306ec396
9 changed files with 823 additions and 29 deletions

View File

@ -1,19 +1,43 @@
# openHASP Changelog # openHASP Changelog
<!-- <!--
## v0.7.0 ## v0.7.0
### Objects ### Objects
- Support for State and Part properties ? Support for State and Part properties
- Set default line_width of line object to 1
### Fonts
- Use embedded TrueType font for default fonts instead of bitmapped font sizes
### Web UI ### Web UI
- _Selectable dark/light theme?_ - _Selectable dark/light theme?_
### Services ### Services
- Add SimpleFTPServer to easily upload and download files to the plate *(one simultanious connection only)* - Change MQTT client from PubSubClient to asynchronic Espressif esp_mstt client
- Add service start/stop mqtt
? Add SimpleFTPServer to easily upload and download files to the plate *(one simultanious connection only)*
### Devices ### Devices
- Add support for Wireless-Tag WT-86-32-3ZW1 - Add GS-T3E Smart Panel
- Add Lilygo Ttgo Lily Pi ESP32
- Add Makerfabs ESP32-S3 SPI
- Add Sunton ESP32-S3 TFT 4.3", 5.0" and 7.0"
- Add Sunton ESP32-2432S028R ESP32-3248S035C ESP32-3248S035R
- Add support for Wireless-Tag WT32-SC01 Plus and WT-86-32-3ZW1
## Bug fixes
- Fix for first touch nog working properly
- Add button GPIOs to input discovery message
### Architecture
- Moved to Tasmota Arduino 2.0.6 and ESP-IDF 4.4.3 (thanks @Jason2866)
- Add support for ESP32-S3 devices
- Add Arduino-GFX display driver
Updated libraries to ArduinoJson 6.20.0, ArduinoStreamUtils 1.7.0, TFT_eSPI 2.4.79 and LovyanGFX 0.5.0
--> -->

View File

@ -0,0 +1,293 @@
#include "Arduino_ESP32RGBPanel_mod.h"
#if defined(ESP32) && (CONFIG_IDF_TARGET_ESP32S3)
Arduino_ESP32RGBPanel_Mod::Arduino_ESP32RGBPanel_Mod(
int8_t cs, int8_t sck, int8_t sda,
int8_t de, int8_t vsync, int8_t hsync, int8_t pclk,
int8_t r0, int8_t r1, int8_t r2, int8_t r3, int8_t r4,
int8_t g0, int8_t g1, int8_t g2, int8_t g3, int8_t g4, int8_t g5,
int8_t b0, int8_t b1, int8_t b2, int8_t b3, int8_t b4,
bool useBigEndian)
: _cs(cs), _sck(sck), _sda(sda),
_de(de), _vsync(vsync), _hsync(hsync), _pclk(pclk),
_r0(r0), _r1(r1), _r2(r2), _r3(r3), _r4(r4),
_g0(g0), _g1(g1), _g2(g2), _g3(g3), _g4(g4), _g5(g5),
_b0(b0), _b1(b1), _b2(b2), _b3(b3), _b4(b4),
_useBigEndian(useBigEndian)
{
}
void Arduino_ESP32RGBPanel_Mod::begin(int32_t speed, int8_t dataMode)
{
if (speed == GFX_NOT_DEFINED)
{
#ifdef CONFIG_SPIRAM_MODE_QUAD
_speed = 6000000L;
#else
_speed = 12000000L;
#endif
}
else
{
_speed = speed;
}
UNUSED(dataMode);
if (_cs != GFX_NOT_DEFINED)
{
pinMode(_cs, OUTPUT);
digitalWrite(_cs, HIGH); // disable chip select
}
if (_cs >= 32)
{
_csPinMask = digitalPinToBitMask(_cs);
_csPortSet = (PORTreg_t)&GPIO.out1_w1ts.val;
_csPortClr = (PORTreg_t)&GPIO.out1_w1tc.val;
}
else
{
_csPinMask = digitalPinToBitMask(_cs);
_csPortSet = (PORTreg_t)&GPIO.out_w1ts;
_csPortClr = (PORTreg_t)&GPIO.out_w1tc;
}
if (_sck != GFX_NOT_DEFINED)
{
pinMode(_sck, OUTPUT);
digitalWrite(_sck, LOW);
}
if (_sck >= 32)
{
_sckPinMask = digitalPinToBitMask(_sck);
_sckPortSet = (PORTreg_t)&GPIO.out1_w1ts.val;
_sckPortClr = (PORTreg_t)&GPIO.out1_w1tc.val;
}
else
{
_sckPinMask = digitalPinToBitMask(_sck);
_sckPortSet = (PORTreg_t)&GPIO.out_w1ts;
_sckPortClr = (PORTreg_t)&GPIO.out_w1tc;
}
if (_sda != GFX_NOT_DEFINED)
{
pinMode(_sda, OUTPUT);
digitalWrite(_sda, LOW);
}
if (_sda >= 32)
{
_sdaPinMask = digitalPinToBitMask(_sda);
_sdaPortSet = (PORTreg_t)&GPIO.out1_w1ts.val;
_sdaPortClr = (PORTreg_t)&GPIO.out1_w1tc.val;
}
else
{
_sdaPinMask = digitalPinToBitMask(_sda);
_sdaPortSet = (PORTreg_t)&GPIO.out_w1ts;
_sdaPortClr = (PORTreg_t)&GPIO.out_w1tc;
}
}
void Arduino_ESP32RGBPanel_Mod::beginWrite()
{
CS_LOW();
}
void Arduino_ESP32RGBPanel_Mod::endWrite()
{
CS_HIGH();
}
void Arduino_ESP32RGBPanel_Mod::writeCommand(uint8_t c)
{
// D/C bit, command
SDA_LOW();
SCK_HIGH();
SCK_LOW();
uint8_t bit = 0x80;
while (bit)
{
if (c & bit)
{
SDA_HIGH();
}
else
{
SDA_LOW();
}
SCK_HIGH();
bit >>= 1;
SCK_LOW();
}
}
void Arduino_ESP32RGBPanel_Mod::writeCommand16(uint16_t)
{
}
void Arduino_ESP32RGBPanel_Mod::write(uint8_t d)
{
// D/C bit, data
SDA_HIGH();
SCK_HIGH();
SCK_LOW();
uint8_t bit = 0x80;
while (bit)
{
if (d & bit)
{
SDA_HIGH();
}
else
{
SDA_LOW();
}
SCK_HIGH();
bit >>= 1;
SCK_LOW();
}
}
void Arduino_ESP32RGBPanel_Mod::write16(uint16_t)
{
}
void Arduino_ESP32RGBPanel_Mod::writeRepeat(uint16_t p, uint32_t len)
{
}
void Arduino_ESP32RGBPanel_Mod::writePixels(uint16_t *data, uint32_t len)
{
}
void Arduino_ESP32RGBPanel_Mod::writeBytes(uint8_t *data, uint32_t len)
{
}
void Arduino_ESP32RGBPanel_Mod::writePattern(uint8_t *data, uint8_t len, uint32_t repeat)
{
}
uint16_t *Arduino_ESP32RGBPanel_Mod::getFrameBuffer(
uint16_t w, uint16_t h,
uint16_t hsync_pulse_width, uint16_t hsync_back_porch, uint16_t hsync_front_porch, uint16_t hsync_polarity,
uint16_t vsync_pulse_width, uint16_t vsync_back_porch, uint16_t vsync_front_porch, uint16_t vsync_polarity,
uint16_t pclk_active_neg, int32_t prefer_speed)
{
esp_lcd_rgb_panel_config_t *_panel_config = (esp_lcd_rgb_panel_config_t *)heap_caps_calloc(1, sizeof(esp_lcd_rgb_panel_config_t), MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL);
_panel_config->clk_src = LCD_CLK_SRC_PLL160M;
_panel_config->timings.pclk_hz = (prefer_speed == GFX_NOT_DEFINED) ? _speed : prefer_speed;
_panel_config->timings.h_res = w;
_panel_config->timings.v_res = h;
// The following parameters should refer to LCD spec
_panel_config->timings.hsync_pulse_width = hsync_pulse_width;
_panel_config->timings.hsync_back_porch = hsync_back_porch;
_panel_config->timings.hsync_front_porch = hsync_front_porch;
_panel_config->timings.vsync_pulse_width = vsync_pulse_width;
_panel_config->timings.vsync_back_porch = vsync_back_porch;
_panel_config->timings.vsync_front_porch = vsync_front_porch;
_panel_config->timings.flags.hsync_idle_low = (hsync_polarity == 0) ? 1 : 0;
_panel_config->timings.flags.vsync_idle_low = (vsync_polarity == 0) ? 1 : 0;
_panel_config->timings.flags.de_idle_high = 0;
_panel_config->timings.flags.pclk_active_neg = pclk_active_neg;
_panel_config->timings.flags.pclk_idle_high = 0;
_panel_config->data_width = 16; // RGB565 in parallel mode, thus 16bit in width
_panel_config->sram_trans_align = 8;
_panel_config->psram_trans_align = 64;
_panel_config->hsync_gpio_num = _hsync;
_panel_config->vsync_gpio_num = _vsync;
_panel_config->de_gpio_num = _de;
_panel_config->pclk_gpio_num = _pclk;
if (_useBigEndian)
{
_panel_config->data_gpio_nums[0] = _g3;
_panel_config->data_gpio_nums[1] = _g4;
_panel_config->data_gpio_nums[2] = _g5;
_panel_config->data_gpio_nums[3] = _r0;
_panel_config->data_gpio_nums[4] = _r1;
_panel_config->data_gpio_nums[5] = _r2;
_panel_config->data_gpio_nums[6] = _r3;
_panel_config->data_gpio_nums[7] = _r4;
_panel_config->data_gpio_nums[8] = _b0;
_panel_config->data_gpio_nums[9] = _b1;
_panel_config->data_gpio_nums[10] = _b2;
_panel_config->data_gpio_nums[11] = _b3;
_panel_config->data_gpio_nums[12] = _b4;
_panel_config->data_gpio_nums[13] = _g0;
_panel_config->data_gpio_nums[14] = _g1;
_panel_config->data_gpio_nums[15] = _g2;
}
else
{
_panel_config->data_gpio_nums[0] = _b0;
_panel_config->data_gpio_nums[1] = _b1;
_panel_config->data_gpio_nums[2] = _b2;
_panel_config->data_gpio_nums[3] = _b3;
_panel_config->data_gpio_nums[4] = _b4;
_panel_config->data_gpio_nums[5] = _g0;
_panel_config->data_gpio_nums[6] = _g1;
_panel_config->data_gpio_nums[7] = _g2;
_panel_config->data_gpio_nums[8] = _g3;
_panel_config->data_gpio_nums[9] = _g4;
_panel_config->data_gpio_nums[10] = _g5;
_panel_config->data_gpio_nums[11] = _r0;
_panel_config->data_gpio_nums[12] = _r1;
_panel_config->data_gpio_nums[13] = _r2;
_panel_config->data_gpio_nums[14] = _r3;
_panel_config->data_gpio_nums[15] = _r4;
}
_panel_config->disp_gpio_num = GPIO_NUM_NC;
_panel_config->flags.disp_active_low = 0;
_panel_config->flags.relax_on_idle = 0;
_panel_config->flags.fb_in_psram = 1; // allocate frame buffer in PSRAM
ESP_ERROR_CHECK(esp_lcd_new_rgb_panel(_panel_config, &_panel_handle));
ESP_ERROR_CHECK(esp_lcd_panel_reset(_panel_handle));
ESP_ERROR_CHECK(esp_lcd_panel_init(_panel_handle));
uint16_t color = random(0xffff);
ESP_ERROR_CHECK(_panel_handle->draw_bitmap(_panel_handle, 0, 0, 1, 1, &color));
_rgb_panel = __containerof(_panel_handle, esp_rgb_panel_t, base);
return (uint16_t *)_rgb_panel->fb;
}
INLINE void Arduino_ESP32RGBPanel_Mod::CS_HIGH(void)
{
*_csPortSet = _csPinMask;
}
INLINE void Arduino_ESP32RGBPanel_Mod::CS_LOW(void)
{
*_csPortClr = _csPinMask;
}
INLINE void Arduino_ESP32RGBPanel_Mod::SCK_HIGH(void)
{
*_sckPortSet = _sckPinMask;
}
INLINE void Arduino_ESP32RGBPanel_Mod::SCK_LOW(void)
{
*_sckPortClr = _sckPinMask;
}
INLINE void Arduino_ESP32RGBPanel_Mod::SDA_HIGH(void)
{
*_sdaPortSet = _sdaPinMask;
}
INLINE void Arduino_ESP32RGBPanel_Mod::SDA_LOW(void)
{
*_sdaPortClr = _sdaPinMask;
}
#endif // #if defined(ESP32) && (CONFIG_IDF_TARGET_ESP32S3)

View File

@ -0,0 +1,122 @@
#include "Arduino_DataBus.h"
#if defined(ESP32) && (CONFIG_IDF_TARGET_ESP32S3)
#include "databus/Arduino_ESP32RGBPanel.h" // struct esp_rgb_panel_t
#ifndef _ARDUINO_ESP32RGBPANEL_MOD_H_
#define _ARDUINO_ESP32RGBPANEL_MOD_H_
#include "esp_lcd_panel_io.h"
#include "esp_lcd_panel_rgb.h"
#include "esp_lcd_panel_vendor.h"
#include "esp_lcd_panel_ops.h"
#include "esp_lcd_panel_interface.h"
#include "esp_private/gdma.h"
#include "esp_pm.h"
#include "hal/dma_types.h"
#include "hal/lcd_hal.h"
#include "hal/lcd_ll.h"
#include "esp32s3/rom/cache.h"
// This function is located in ROM (also see esp_rom/${target}/ld/${target}.rom.ld)
extern int Cache_WriteBack_Addr(uint32_t addr, uint32_t size);
// // extract from esp-idf esp_lcd_rgb_panel.c
// struct esp_rgb_panel_t
// {
// esp_lcd_panel_t base; // Base class of generic lcd panel
// int panel_id; // LCD panel ID
// lcd_hal_context_t hal; // Hal layer object
// size_t data_width; // Number of data lines (e.g. for RGB565, the data width is 16)
// size_t sram_trans_align; // Alignment for framebuffer that allocated in SRAM
// size_t psram_trans_align; // Alignment for framebuffer that allocated in PSRAM
// int disp_gpio_num; // Display control GPIO, which is used to perform action like "disp_off"
// intr_handle_t intr; // LCD peripheral interrupt handle
// esp_pm_lock_handle_t pm_lock; // Power management lock
// size_t num_dma_nodes; // Number of DMA descriptors that used to carry the frame buffer
// uint8_t *fb; // Frame buffer
// size_t fb_size; // Size of frame buffer
// int data_gpio_nums[SOC_LCD_RGB_DATA_WIDTH]; // GPIOs used for data lines, we keep these GPIOs for action like "invert_color"
// size_t resolution_hz; // Peripheral clock resolution
// esp_lcd_rgb_timing_t timings; // RGB timing parameters (e.g. pclk, sync pulse, porch width)
// gdma_channel_handle_t dma_chan; // DMA channel handle
// esp_lcd_rgb_panel_frame_trans_done_cb_t on_frame_trans_done; // Callback, invoked after frame trans done
// void *user_ctx; // Reserved user's data of callback functions
// int x_gap; // Extra gap in x coordinate, it's used when calculate the flush window
// int y_gap; // Extra gap in y coordinate, it's used when calculate the flush window
// struct
// {
// unsigned int disp_en_level : 1; // The level which can turn on the screen by `disp_gpio_num`
// unsigned int stream_mode : 1; // If set, the LCD transfers data continuously, otherwise, it stops refreshing the LCD when transaction done
// unsigned int fb_in_psram : 1; // Whether the frame buffer is in PSRAM
// } flags;
// dma_descriptor_t dma_nodes[]; // DMA descriptor pool of size `num_dma_nodes`
// };
class Arduino_ESP32RGBPanel_Mod : public Arduino_DataBus
{
public:
Arduino_ESP32RGBPanel_Mod(
int8_t cs, int8_t sck, int8_t sda,
int8_t de, int8_t vsync, int8_t hsync, int8_t pclk,
int8_t r0, int8_t r1, int8_t r2, int8_t r3, int8_t r4,
int8_t g0, int8_t g1, int8_t g2, int8_t g3, int8_t g4, int8_t g5,
int8_t b0, int8_t b1, int8_t b2, int8_t b3, int8_t b4,
bool useBigEndian = false);
void begin(int32_t speed = GFX_NOT_DEFINED, int8_t dataMode = GFX_NOT_DEFINED) override;
void beginWrite() override;
void endWrite() override;
void writeCommand(uint8_t) override;
void writeCommand16(uint16_t) override;
void write(uint8_t) override;
void write16(uint16_t) override;
void writeRepeat(uint16_t p, uint32_t len) override;
void writePixels(uint16_t *data, uint32_t len) override;
void writeBytes(uint8_t *data, uint32_t len) override;
void writePattern(uint8_t *data, uint8_t len, uint32_t repeat) override;
uint16_t *getFrameBuffer(
uint16_t w, uint16_t h,
uint16_t hsync_pulse_width = 18, uint16_t hsync_back_porch = 24, uint16_t hsync_front_porch = 6, uint16_t hsync_polarity = 1,
uint16_t vsync_pulse_width = 10, uint16_t vsync_back_porch = 16, uint16_t vsync_front_porch = 4, uint16_t vsync_polarity = 1,
uint16_t pclk_active_neg = 0, int32_t prefer_speed = GFX_NOT_DEFINED);
esp_lcd_panel_handle_t _panel_handle = NULL;
protected:
private:
INLINE void CS_HIGH(void);
INLINE void CS_LOW(void);
INLINE void SCK_HIGH(void);
INLINE void SCK_LOW(void);
INLINE void SDA_HIGH(void);
INLINE void SDA_LOW(void);
int32_t _speed;
int8_t _dataMode;
int8_t _cs, _sck, _sda;
int8_t _de, _vsync, _hsync, _pclk;
int8_t _r0, _r1, _r2, _r3, _r4;
int8_t _g0, _g1, _g2, _g3, _g4, _g5;
int8_t _b0, _b1, _b2, _b3, _b4;
bool _useBigEndian;
esp_rgb_panel_t *_rgb_panel;
PORTreg_t _csPortSet; ///< PORT register for chip select SET
PORTreg_t _csPortClr; ///< PORT register for chip select CLEAR
PORTreg_t _sckPortSet; ///< PORT register for SCK SET
PORTreg_t _sckPortClr; ///< PORT register for SCK CLEAR
PORTreg_t _sdaPortSet; ///< PORT register for SCK SET
PORTreg_t _sdaPortClr; ///< PORT register for SCK CLEAR
uint32_t _csPinMask; ///< Bitmask for chip select
uint32_t _sckPinMask; ///< Bitmask for SCK
uint32_t _sdaPinMask; ///< Bitmask for SCK
};
#endif // _ARDUINO_ESP32RGBPANEL_H_
#endif // #if defined(ESP32) && (CONFIG_IDF_TARGET_ESP32S3)

View File

@ -0,0 +1,263 @@
#include "Arduino_DataBus.h"
#if defined(ESP32) && (CONFIG_IDF_TARGET_ESP32S3)
#include "Arduino_GFX.h"
#include "Arduino_RPi_DPI_RGBPanel_mod.h"
#include "Arduino_ESP32RGBPanel_mod.h"
Arduino_RGBPanel_Mod::Arduino_RGBPanel_Mod(Arduino_ESP32RGBPanel_Mod* bus, int16_t w, uint16_t hsync_polarity,
uint16_t hsync_front_porch, uint16_t hsync_pulse_width,
uint16_t hsync_back_porch, int16_t h, uint16_t vsync_polarity,
uint16_t vsync_front_porch, uint16_t vsync_pulse_width,
uint16_t vsync_back_porch, uint16_t pclk_active_neg,
int32_t prefer_speed, bool auto_flush)
: Arduino_GFX(w, h), _bus(bus), _hsync_polarity(hsync_polarity), _hsync_front_porch(hsync_front_porch),
_hsync_pulse_width(hsync_pulse_width), _hsync_back_porch(hsync_back_porch), _vsync_polarity(vsync_polarity),
_vsync_front_porch(vsync_front_porch), _vsync_pulse_width(vsync_pulse_width), _vsync_back_porch(vsync_back_porch),
_pclk_active_neg(pclk_active_neg), _prefer_speed(prefer_speed), _auto_flush(auto_flush)
{
_framebuffer_size = w * h * 2;
}
void Arduino_RGBPanel_Mod::begin(int32_t speed)
{
_bus->begin(speed);
_framebuffer = _bus->getFrameBuffer(_width, _height, _hsync_pulse_width, _hsync_back_porch, _hsync_front_porch,
_hsync_polarity, _vsync_pulse_width, _vsync_back_porch, _vsync_front_porch,
_vsync_polarity, _pclk_active_neg, _prefer_speed);
}
void Arduino_RGBPanel_Mod::writePixelPreclipped(int16_t x, int16_t y, uint16_t color)
{
uint16_t* fb = _framebuffer;
fb += (int32_t)y * _width;
fb += x;
*fb = color;
if(_auto_flush) {
Cache_WriteBack_Addr((uint32_t)fb, 2);
}
}
void Arduino_RGBPanel_Mod::writeFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color)
{
if(_ordered_in_range(x, 0, _max_x) && h) { // X on screen, nonzero height
if(h < 0) { // If negative height...
y += h + 1; // Move Y to top edge
h = -h; // Use positive height
}
if(y <= _max_y) { // Not off bottom
int16_t y2 = y + h - 1;
if(y2 >= 0) { // Not off top
// Line partly or fully overlaps screen
if(y < 0) {
y = 0;
h = y2 + 1;
} // Clip top
if(y2 > _max_y) {
h = _max_y - y + 1;
} // Clip bottom
uint16_t* fb = _framebuffer + ((int32_t)y * _width) + x;
if(_auto_flush) {
while(h--) {
*fb = color;
Cache_WriteBack_Addr((uint32_t)fb, 2);
fb += _width;
}
} else {
while(h--) {
*fb = color;
fb += _width;
}
}
}
}
}
}
void Arduino_RGBPanel_Mod::writeFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color)
{
if(_ordered_in_range(y, 0, _max_y) && w) { // Y on screen, nonzero width
if(w < 0) { // If negative width...
x += w + 1; // Move X to left edge
w = -w; // Use positive width
}
if(x <= _max_x) { // Not off right
int16_t x2 = x + w - 1;
if(x2 >= 0) { // Not off left
// Line partly or fully overlaps screen
if(x < 0) {
x = 0;
w = x2 + 1;
} // Clip left
if(x2 > _max_x) {
w = _max_x - x + 1;
} // Clip right
uint16_t* fb = _framebuffer + ((int32_t)y * _width) + x;
uint32_t cachePos = (uint32_t)fb;
int16_t writeSize = w * 2;
while(w--) {
*(fb++) = color;
}
if(_auto_flush) {
Cache_WriteBack_Addr(cachePos, writeSize);
}
}
}
}
}
void Arduino_RGBPanel_Mod::writeFillRectPreclipped(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color)
{
uint16_t* row = _framebuffer;
row += y * _width;
uint32_t cachePos = (uint32_t)row;
row += x;
for(int j = 0; j < h; j++) {
for(int i = 0; i < w; i++) {
row[i] = color;
}
row += _width;
}
if(_auto_flush) {
Cache_WriteBack_Addr(cachePos, _width * h * 2);
}
}
void Arduino_RGBPanel_Mod::setRotation(uint8_t r)
{
esp_err_t err = esp_lcd_panel_swap_xy(_bus->_panel_handle, r & 1);
err = esp_lcd_panel_mirror(_bus->_panel_handle, r & 4, r & 2);
}
void Arduino_RGBPanel_Mod::invertDisplay(bool i)
{
esp_err_t err = esp_lcd_panel_invert_color(_bus->_panel_handle, i);
}
void Arduino_RGBPanel_Mod::draw16bitRGBBitmap(int16_t x, int16_t y, uint16_t* bitmap, int16_t w, int16_t h)
{
esp_err_t err = esp_lcd_panel_draw_bitmap(_bus->_panel_handle, x, y, x + w, y + h, bitmap);
return;
if(((x + w - 1) < 0) || // Outside left
((y + h - 1) < 0) || // Outside top
(x > _max_x) || // Outside right
(y > _max_y) // Outside bottom
) {
return;
} else {
int16_t xskip = 0;
if((y + h - 1) > _max_y) {
h -= (y + h - 1) - _max_y;
}
if(y < 0) {
bitmap -= y * w;
h += y;
y = 0;
}
if((x + w - 1) > _max_x) {
xskip = (x + w - 1) - _max_x;
w -= xskip;
}
if(x < 0) {
bitmap -= x;
xskip -= x;
w += x;
x = 0;
}
uint16_t* row = _framebuffer;
row += y * _width;
uint32_t cachePos = (uint32_t)row;
row += x;
if(((_width & 1) == 0) && ((xskip & 1) == 0) && ((w & 1) == 0)) {
uint32_t* row2 = (uint32_t*)row;
uint32_t* bitmap2 = (uint32_t*)bitmap;
int16_t _width2 = _width >> 1;
int16_t xskip2 = xskip >> 1;
int16_t w2 = w >> 1;
for(int16_t j = 0; j < h; j++) {
for(int16_t i = 0; i < w2; i++) {
row2[i] = *bitmap2++;
}
bitmap2 += xskip2;
row2 += _width2;
}
} else {
for(int j = 0; j < h; j++) {
for(int i = 0; i < w; i++) {
row[i] = *bitmap++;
}
bitmap += xskip;
row += _width;
}
}
if(_auto_flush) {
Cache_WriteBack_Addr(cachePos, _width * h * 2);
}
}
}
void Arduino_RGBPanel_Mod::draw16bitBeRGBBitmap(int16_t x, int16_t y, uint16_t* bitmap, int16_t w, int16_t h)
{
if(((x + w - 1) < 0) || // Outside left
((y + h - 1) < 0) || // Outside top
(x > _max_x) || // Outside right
(y > _max_y) // Outside bottom
) {
return;
} else {
int16_t xskip = 0;
if((y + h - 1) > _max_y) {
h -= (y + h - 1) - _max_y;
}
if(y < 0) {
bitmap -= y * w;
h += y;
y = 0;
}
if((x + w - 1) > _max_x) {
xskip = (x + w - 1) - _max_x;
w -= xskip;
}
if(x < 0) {
bitmap -= x;
xskip -= x;
w += x;
x = 0;
}
uint16_t* row = _framebuffer;
row += y * _width;
uint32_t cachePos = (uint32_t)row;
row += x;
uint16_t color;
for(int j = 0; j < h; j++) {
for(int i = 0; i < w; i++) {
color = *bitmap++;
MSB_16_SET(row[i], color);
}
bitmap += xskip;
row += _width;
}
if(_auto_flush) {
Cache_WriteBack_Addr(cachePos, _width * h * 2);
}
}
}
void Arduino_RGBPanel_Mod::flush(void)
{
if(!_auto_flush) {
Cache_WriteBack_Addr((uint32_t)_framebuffer, _framebuffer_size);
}
}
uint16_t* Arduino_RGBPanel_Mod::getFramebuffer()
{
return _framebuffer;
}
#endif // #if defined(ESP32) && (CONFIG_IDF_TARGET_ESP32S3)

View File

@ -0,0 +1,56 @@
#include "Arduino_DataBus.h"
#if defined(ESP32) && (CONFIG_IDF_TARGET_ESP32S3)
#ifndef _ARDUINO_RPI_DPI_RGBPANEL_MOD_H_
#define _ARDUINO_RPI_DPI_RGBPANEL_MOD_H_
#include "Arduino_GFX.h"
#include "Arduino_ESP32RGBPanel_mod.h"
class Arduino_RGBPanel_Mod : public Arduino_GFX
{
public:
Arduino_RGBPanel_Mod(
Arduino_ESP32RGBPanel_Mod *bus,
int16_t w, uint16_t hsync_polarity, uint16_t hsync_front_porch, uint16_t hsync_pulse_width, uint16_t hsync_back_porch,
int16_t h, uint16_t vsync_polarity, uint16_t vsync_front_porch, uint16_t vsync_pulse_width, uint16_t vsync_back_porch,
uint16_t pclk_active_neg = 0, int32_t prefer_speed = GFX_NOT_DEFINED, bool auto_flush = true);
void begin(int32_t speed = GFX_NOT_DEFINED) override;
void writePixelPreclipped(int16_t x, int16_t y, uint16_t color) override;
void writeFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color) override;
void writeFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color) override;
void writeFillRectPreclipped(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color) override;
void draw16bitRGBBitmap(int16_t x, int16_t y, uint16_t *bitmap, int16_t w, int16_t h) override;
void draw16bitBeRGBBitmap(int16_t x, int16_t y, uint16_t *bitmap, int16_t w, int16_t h) override;
void flush(void) override;
void setRotation(uint8_t r);
void invertDisplay(bool i);
uint16_t *getFramebuffer();
Arduino_ESP32RGBPanel_Mod *_bus;
protected:
uint16_t *_framebuffer;
size_t _framebuffer_size;
uint16_t _hsync_polarity;
uint16_t _hsync_front_porch;
uint16_t _hsync_pulse_width;
uint16_t _hsync_back_porch;
uint16_t _vsync_polarity;
uint16_t _vsync_front_porch;
uint16_t _vsync_pulse_width;
uint16_t _vsync_back_porch;
uint16_t _pclk_active_neg;
int32_t _prefer_speed;
bool _auto_flush;
private:
};
#endif // _ARDUINO_RPI_DPI_RGBPANEL_H_
#endif // #if defined(ESP32) && (CONFIG_IDF_TARGET_ESP32S3)

View File

@ -26,6 +26,16 @@
#ifndef TFT_BUSY #ifndef TFT_BUSY
#define TFT_BUSY -1 #define TFT_BUSY -1
#endif #endif
#ifndef TFT_CS
#define TFT_CS -1
#endif
#ifndef TFT_RST
#define TFT_RST -1
#endif
#ifndef SPI_FREQUENCY
#define SPI_FREQUENCY 40000000
#endif
#ifndef TFT_D0 #ifndef TFT_D0
#define TFT_D0 -1 #define TFT_D0 -1

View File

@ -5,6 +5,8 @@
#include "tft_driver_arduinogfx.h" #include "tft_driver_arduinogfx.h"
#include <Preferences.h> #include <Preferences.h>
#include "Arduino_RPi_DPI_RGBPanel_mod.h"
#include "Arduino_ESP32RGBPanel_mod.h"
namespace dev { namespace dev {
void tftPinInfo(const __FlashStringHelper* pinfunction, int8_t pin) void tftPinInfo(const __FlashStringHelper* pinfunction, int8_t pin)
@ -21,12 +23,12 @@ void ArduinoGfx::init(int w, int h)
{ {
LOG_TRACE(TAG_TFT, F(D_SERVICE_STARTING)); LOG_TRACE(TAG_TFT, F(D_SERVICE_STARTING));
#if(TFT_WIDTH == 480) && (TFT_HEIGHT == 480) && defined(GC9503V_DRIVER) #if(TFT_WIDTH == 480) && (TFT_HEIGHT == 480) && defined(GC9503V_DRIVER)
Arduino_DataBus* bus = new Arduino_SWSPI(TFT_DC, TFT_CS, TFT_SCLK, TFT_MOSI, TFT_MISO); Arduino_DataBus* bus = new Arduino_SWSPI(TFT_DC, TFT_CS, TFT_SCLK, TFT_MOSI, TFT_MISO);
Arduino_ESP32RGBPanel* rgbpanel = new Arduino_ESP32RGBPanel( Arduino_ESP32RGBPanel* rgbpanel = new Arduino_ESP32RGBPanel(
TFT_DE, TFT_VSYNC, TFT_HSYNC, TFT_PCLK, TFT_R0, TFT_R1, TFT_R2, TFT_R3, TFT_R4, TFT_G0, TFT_G1, TFT_G2, TFT_DE, TFT_VSYNC, TFT_HSYNC, TFT_PCLK, TFT_R0, TFT_R1, TFT_R2, TFT_R3, TFT_R4, TFT_G0, TFT_G1, TFT_G2, TFT_G3,
TFT_G3, TFT_G4, TFT_G5, TFT_B0, TFT_B1, TFT_B2, TFT_B3, TFT_B4, TFT_HSYNC_POLARITY, TFT_HSYNC_FRONT_PORCH, TFT_G4, TFT_G5, TFT_B0, TFT_B1, TFT_B2, TFT_B3, TFT_B4, TFT_HSYNC_POLARITY, TFT_HSYNC_FRONT_PORCH,
TFT_HSYNC_PULSE_WIDTH, TFT_HSYNC_BACK_PORCH, TFT_VSYNC_POLARITY, TFT_VSYNC_FRONT_PORCH, TFT_HSYNC_PULSE_WIDTH, TFT_HSYNC_BACK_PORCH, TFT_VSYNC_POLARITY, TFT_VSYNC_FRONT_PORCH, TFT_VSYNC_PULSE_WIDTH,
TFT_VSYNC_PULSE_WIDTH, TFT_VSYNC_BACK_PORCH); TFT_VSYNC_BACK_PORCH);
tft = new Arduino_RGB_Display(w, h, rgbpanel, 0 /* rotation */, TFT_AUTO_FLUSH, bus, TFT_RST, tft = new Arduino_RGB_Display(w, h, rgbpanel, 0 /* rotation */, TFT_AUTO_FLUSH, bus, TFT_RST,
gc9503v_type1_init_operations, sizeof(gc9503v_type1_init_operations)); gc9503v_type1_init_operations, sizeof(gc9503v_type1_init_operations));
@ -42,15 +44,16 @@ void ArduinoGfx::init(int w, int h)
480 /* height */, st7701_type1_init_operations, 480 /* height */, st7701_type1_init_operations,
sizeof(st7701_type1_init_operations), true /* BGR */); sizeof(st7701_type1_init_operations), true /* BGR */);
#elif 1 #elif 1
Arduino_ESP32RGBPanel* bus = new Arduino_ESP32RGBPanel( Arduino_ESP32RGBPanel_Mod* bus = new Arduino_ESP32RGBPanel_Mod(
GFX_NOT_DEFINED /* CS */, GFX_NOT_DEFINED /* SCK */, GFX_NOT_DEFINED /* SDA */, TFT_DE, TFT_VSYNC, TFT_HSYNC, GFX_NOT_DEFINED /* CS */, GFX_NOT_DEFINED /* SCK */, GFX_NOT_DEFINED /* SDA */, TFT_DE, TFT_VSYNC, TFT_HSYNC,
TFT_PCLK, TFT_R0, TFT_R1, TFT_R2, TFT_R3, TFT_R4, TFT_G0, TFT_G1, TFT_G2, TFT_G3, TFT_G4, TFT_G5, TFT_B0, TFT_PCLK, TFT_R0, TFT_R1, TFT_R2, TFT_R3, TFT_R4, TFT_G0, TFT_G1, TFT_G2, TFT_G3, TFT_G4, TFT_G5, TFT_B0,
TFT_B1, TFT_B2, TFT_B3, TFT_B4); TFT_B1, TFT_B2, TFT_B3, TFT_B4);
tft = new Arduino_RPi_DPI_RGBPanel(bus, TFT_WIDTH, TFT_HSYNC_POLARITY, TFT_HSYNC_FRONT_PORCH, TFT_HSYNC_PULSE_WIDTH, tft = new Arduino_RGBPanel_Mod(bus, TFT_WIDTH, TFT_HSYNC_POLARITY, TFT_HSYNC_FRONT_PORCH, TFT_HSYNC_PULSE_WIDTH,
TFT_HSYNC_BACK_PORCH, TFT_HEIGHT, TFT_VSYNC_POLARITY, TFT_VSYNC_FRONT_PORCH, TFT_HSYNC_BACK_PORCH, TFT_HEIGHT, TFT_VSYNC_POLARITY, TFT_VSYNC_FRONT_PORCH,
TFT_VSYNC_PULSE_WIDTH, TFT_VSYNC_BACK_PORCH, TFT_PCLK_ACTIVE_NEG, TFT_VSYNC_PULSE_WIDTH, TFT_VSYNC_BACK_PORCH, TFT_PCLK_ACTIVE_NEG, TFT_PREFER_SPEED,
TFT_PREFER_SPEED, TFT_AUTO_FLUSH); TFT_AUTO_FLUSH);
// fb = ((Arduino_RGBPanel_Mod*)tft)->getFramebuffer();
#endif #endif
/* TFT init */ /* TFT init */
@ -172,8 +175,7 @@ void ArduinoGfx::splashscreen()
tft->fillScreen(bgColor.full); tft->fillScreen(bgColor.full);
int x = (tft->width() - logoWidth) / 2; int x = (tft->width() - logoWidth) / 2;
int y = (tft->height() - logoHeight) / 2; int y = (tft->height() - logoHeight) / 2;
tft->drawXBitmap(x, y, logoImage, logoWidth, logoHeight, fgColor.full); tft->drawXBitmap(x, y, logoImage, logoWidth, logoHeight, fgColor.full);
// tft.fillSmoothRoundRect(x, y, logoWidth, logoWidth, 15, fgColor.full);
} }
void ArduinoGfx::set_rotation(uint8_t rotation) void ArduinoGfx::set_rotation(uint8_t rotation)

View File

@ -16,7 +16,7 @@
#include "hasp_gui.h" #include "hasp_gui.h"
#include "hasp_oobe.h" #include "hasp_oobe.h"
//#include "tpcal.h" // #include "tpcal.h"
#define BACKLIGHT_CHANNEL 0 // pwm channel 0-15 #define BACKLIGHT_CHANNEL 0 // pwm channel 0-15
@ -291,16 +291,18 @@ void guiSetup()
#else // Use lvgl transformations #else // Use lvgl transformations
static lv_disp_drv_t disp_drv; static lv_disp_drv_t disp_drv;
lv_disp_drv_init(&disp_drv); lv_disp_drv_init(&disp_drv);
disp_drv.buffer = &disp_buf; disp_drv.buffer = &disp_buf;
disp_drv.flush_cb = gui_flush_cb; disp_drv.flush_cb = gui_flush_cb;
disp_drv.hor_res = tft_width;
disp_drv.ver_res = tft_height;
disp_drv.hor_res = tft_width; #if defined(HASP_LV_USE_SW_ROTATE)
disp_drv.ver_res = tft_height; disp_drv.sw_rotate = 1; // enable special bit order in framebuffer bitmaps
#endif
lv_disp_rot_t rotation[] = {LV_DISP_ROT_NONE, LV_DISP_ROT_270, LV_DISP_ROT_180, LV_DISP_ROT_90}; lv_disp_rot_t rotation[] = {LV_DISP_ROT_NONE, LV_DISP_ROT_270, LV_DISP_ROT_180, LV_DISP_ROT_90};
lv_disp_t* display = lv_disp_drv_register(&disp_drv); lv_disp_t* display = lv_disp_drv_register(&disp_drv);
lv_disp_set_rotation(display, rotation[(4 + gui_settings.rotation - TFT_ROTATION) % 4]); lv_disp_set_rotation(display, rotation[(4 + gui_settings.rotation - TFT_ROTATION) % 4]);
#endif #endif
disp_drv.monitor_cb = gui_monitor_cb; disp_drv.monitor_cb = gui_monitor_cb;
@ -716,6 +718,13 @@ static void gui_screenshot_to_http(lv_disp_drv_t* disp, const lv_area_t* area, l
size_t res = httpClientWrite((uint8_t*)color_p, len); size_t res = httpClientWrite((uint8_t*)color_p, len);
if(res != len) gui_flush_not_complete(); if(res != len) gui_flush_not_complete();
lv_disp_flush_ready(disp);
}
static void gui_screenshot_to_both(lv_disp_drv_t* disp, const lv_area_t* area, lv_color_t* color_p)
{
gui_screenshot_to_http(disp, area, color_p);
// indirect callback to flush screenshot data to the screen // indirect callback to flush screenshot data to the screen
drv_display_flush_cb(disp, area, color_p); drv_display_flush_cb(disp, area, color_p);
} }
@ -735,15 +744,28 @@ void guiTakeScreenshot()
if(httpClientWrite(buffer, sizeof(buffer)) == sizeof(buffer)) { if(httpClientWrite(buffer, sizeof(buffer)) == sizeof(buffer)) {
LOG_VERBOSE(TAG_GUI, F("Bitmap header sent")); LOG_VERBOSE(TAG_GUI, F("Bitmap header sent"));
/* Refresh screen to screenshot callback */ lv_disp_t* disp = lv_disp_get_default();
lv_disp_t* disp = lv_disp_get_default(); drv_display_flush_cb = disp->driver.flush_cb; /* store callback */
drv_display_flush_cb = disp->driver.flush_cb; /* store callback */
disp->driver.flush_cb = gui_screenshot_to_http;
lv_obj_invalidate(lv_scr_act());
lv_refr_now(NULL); /* Will call our disp_drv.disp_flush function */
disp->driver.flush_cb = drv_display_flush_cb; /* restore callback */
screenshotIsDirty = false;
if(disp->driver.sw_rotate) {
disp->driver.flush_cb = gui_screenshot_to_http;
disp->driver.sw_rotate = 0;
lv_obj_invalidate(lv_scr_act());
lv_refr_now(NULL); /* Will call our disp_drv.disp_flush function */
disp->driver.flush_cb = drv_display_flush_cb; /* restore callback */
disp->driver.sw_rotate = 1; /* redraw to screen */
lv_obj_invalidate(lv_scr_act());
lv_refr_now(NULL);
} else {
/* Refresh screen to screenshot callback */
disp->driver.flush_cb = gui_screenshot_to_both;
lv_obj_invalidate(lv_scr_act());
lv_refr_now(NULL); /* Will call our disp_drv.disp_flush function */
disp->driver.flush_cb = drv_display_flush_cb; /* restore callback */
}
screenshotIsDirty = false;
LOG_VERBOSE(TAG_GUI, F("Bitmap data flushed to webclient")); LOG_VERBOSE(TAG_GUI, F("Bitmap data flushed to webclient"));
} else { } else {
LOG_ERROR(TAG_GUI, F("Data sent does not match header size")); LOG_ERROR(TAG_GUI, F("Data sent does not match header size"));

View File

@ -18,6 +18,7 @@ build_flags =
;region -- LovyanGFX build options ------------------------ ;region -- LovyanGFX build options ------------------------
-D HASP_USE_ARDUINOGFX=1 -D HASP_USE_ARDUINOGFX=1
-D HASP_LV_USE_SW_ROTATE=1
-D TFT_BCKL=2 -D TFT_BCKL=2
;endregion ;endregion
@ -27,6 +28,7 @@ lib_deps =
${esp32s3.lib_deps} ${esp32s3.lib_deps}
${arduino_esp32s3_v2.lib_deps} ${arduino_esp32s3_v2.lib_deps}
${arduinogfx.lib_deps} ${arduinogfx.lib_deps}
Arduino_RPi_DPI_RGBPanel_mod
${goodix.lib_deps} ${goodix.lib_deps}
lib_ignore = lib_ignore =