diff --git a/CHANGLELOG.md b/CHANGLELOG.md index d2b3d3e6..f4e2837c 100644 --- a/CHANGLELOG.md +++ b/CHANGLELOG.md @@ -1,19 +1,43 @@ # openHASP Changelog diff --git a/lib/Arduino_RPi_DPI_RGBPanel_mod/Arduino_ESP32RGBPanel_mod.cpp b/lib/Arduino_RPi_DPI_RGBPanel_mod/Arduino_ESP32RGBPanel_mod.cpp new file mode 100644 index 00000000..0c793e65 --- /dev/null +++ b/lib/Arduino_RPi_DPI_RGBPanel_mod/Arduino_ESP32RGBPanel_mod.cpp @@ -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) diff --git a/lib/Arduino_RPi_DPI_RGBPanel_mod/Arduino_ESP32RGBPanel_mod.h b/lib/Arduino_RPi_DPI_RGBPanel_mod/Arduino_ESP32RGBPanel_mod.h new file mode 100644 index 00000000..945b2953 --- /dev/null +++ b/lib/Arduino_RPi_DPI_RGBPanel_mod/Arduino_ESP32RGBPanel_mod.h @@ -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) diff --git a/lib/Arduino_RPi_DPI_RGBPanel_mod/Arduino_RPi_DPI_RGBPanel_mod.cpp b/lib/Arduino_RPi_DPI_RGBPanel_mod/Arduino_RPi_DPI_RGBPanel_mod.cpp new file mode 100644 index 00000000..21526b86 --- /dev/null +++ b/lib/Arduino_RPi_DPI_RGBPanel_mod/Arduino_RPi_DPI_RGBPanel_mod.cpp @@ -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) diff --git a/lib/Arduino_RPi_DPI_RGBPanel_mod/Arduino_RPi_DPI_RGBPanel_mod.h b/lib/Arduino_RPi_DPI_RGBPanel_mod/Arduino_RPi_DPI_RGBPanel_mod.h new file mode 100644 index 00000000..543f596f --- /dev/null +++ b/lib/Arduino_RPi_DPI_RGBPanel_mod/Arduino_RPi_DPI_RGBPanel_mod.h @@ -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) diff --git a/src/drv/tft/tft_defines.h b/src/drv/tft/tft_defines.h index f42eddf6..62536d18 100644 --- a/src/drv/tft/tft_defines.h +++ b/src/drv/tft/tft_defines.h @@ -26,6 +26,16 @@ #ifndef TFT_BUSY #define TFT_BUSY -1 #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 #define TFT_D0 -1 diff --git a/src/drv/tft/tft_driver_arduinogfx.cpp b/src/drv/tft/tft_driver_arduinogfx.cpp index 23717e20..07cc897e 100644 --- a/src/drv/tft/tft_driver_arduinogfx.cpp +++ b/src/drv/tft/tft_driver_arduinogfx.cpp @@ -5,6 +5,8 @@ #include "tft_driver_arduinogfx.h" #include +#include "Arduino_RPi_DPI_RGBPanel_mod.h" +#include "Arduino_ESP32RGBPanel_mod.h" namespace dev { 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)); #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( - 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_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_VSYNC_PULSE_WIDTH, TFT_VSYNC_BACK_PORCH); + 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_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_VSYNC_PULSE_WIDTH, + TFT_VSYNC_BACK_PORCH); 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)); @@ -42,15 +44,16 @@ void ArduinoGfx::init(int w, int h) 480 /* height */, st7701_type1_init_operations, sizeof(st7701_type1_init_operations), true /* BGR */); #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, 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 = new Arduino_RPi_DPI_RGBPanel(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_VSYNC_PULSE_WIDTH, TFT_VSYNC_BACK_PORCH, TFT_PCLK_ACTIVE_NEG, - TFT_PREFER_SPEED, TFT_AUTO_FLUSH); + 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_VSYNC_PULSE_WIDTH, TFT_VSYNC_BACK_PORCH, TFT_PCLK_ACTIVE_NEG, TFT_PREFER_SPEED, + TFT_AUTO_FLUSH); + // fb = ((Arduino_RGBPanel_Mod*)tft)->getFramebuffer(); #endif /* TFT init */ @@ -172,8 +175,7 @@ void ArduinoGfx::splashscreen() tft->fillScreen(bgColor.full); int x = (tft->width() - logoWidth) / 2; int y = (tft->height() - logoHeight) / 2; - tft->drawXBitmap(x, y, logoImage, logoWidth, logoHeight, fgColor.full); - // tft.fillSmoothRoundRect(x, y, logoWidth, logoWidth, 15, fgColor.full); + tft->drawXBitmap(x, y, logoImage, logoWidth, logoHeight, fgColor.full); } void ArduinoGfx::set_rotation(uint8_t rotation) diff --git a/src/hasp_gui.cpp b/src/hasp_gui.cpp index 39aca84f..0a492b47 100644 --- a/src/hasp_gui.cpp +++ b/src/hasp_gui.cpp @@ -16,7 +16,7 @@ #include "hasp_gui.h" #include "hasp_oobe.h" -//#include "tpcal.h" +// #include "tpcal.h" #define BACKLIGHT_CHANNEL 0 // pwm channel 0-15 @@ -291,16 +291,18 @@ void guiSetup() #else // Use lvgl transformations static lv_disp_drv_t disp_drv; lv_disp_drv_init(&disp_drv); - disp_drv.buffer = &disp_buf; - disp_drv.flush_cb = gui_flush_cb; + disp_drv.buffer = &disp_buf; + 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; - disp_drv.ver_res = tft_height; +#if defined(HASP_LV_USE_SW_ROTATE) + 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_t* display = lv_disp_drv_register(&disp_drv); lv_disp_set_rotation(display, rotation[(4 + gui_settings.rotation - TFT_ROTATION) % 4]); - #endif 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); 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 drv_display_flush_cb(disp, area, color_p); } @@ -735,15 +744,28 @@ void guiTakeScreenshot() if(httpClientWrite(buffer, sizeof(buffer)) == sizeof(buffer)) { LOG_VERBOSE(TAG_GUI, F("Bitmap header sent")); - /* Refresh screen to screenshot callback */ - lv_disp_t* disp = lv_disp_get_default(); - 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; + lv_disp_t* disp = lv_disp_get_default(); + drv_display_flush_cb = disp->driver.flush_cb; /* store callback */ + 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")); } else { LOG_ERROR(TAG_GUI, F("Data sent does not match header size")); diff --git a/user_setups/esp32s3/sunton-esp32-s3-tft.ini b/user_setups/esp32s3/sunton-esp32-s3-tft.ini index e2a212d5..07f00615 100644 --- a/user_setups/esp32s3/sunton-esp32-s3-tft.ini +++ b/user_setups/esp32s3/sunton-esp32-s3-tft.ini @@ -18,6 +18,7 @@ build_flags = ;region -- LovyanGFX build options ------------------------ -D HASP_USE_ARDUINOGFX=1 + -D HASP_LV_USE_SW_ROTATE=1 -D TFT_BCKL=2 ;endregion @@ -27,6 +28,7 @@ lib_deps = ${esp32s3.lib_deps} ${arduino_esp32s3_v2.lib_deps} ${arduinogfx.lib_deps} + Arduino_RPi_DPI_RGBPanel_mod ${goodix.lib_deps} lib_ignore =