diff --git a/src/lgfx/v1/panel/Panel_NV3041A.cpp b/src/lgfx/v1/panel/Panel_NV3041A.cpp new file mode 100644 index 00000000..5c78f4f6 --- /dev/null +++ b/src/lgfx/v1/panel/Panel_NV3041A.cpp @@ -0,0 +1,533 @@ +/*----------------------------------------------------------------------------/ + * Lovyan GFX - Graphics library for embedded devices. + * + * Original Source: + * https://github.com/lovyan03/LovyanGFX/ + * + * Licence: + * [FreeBSD](https://github.com/lovyan03/LovyanGFX/blob/master/license.txt) + * + * Author: + * [lovyan03](https://twitter.com/lovyan03) + * + * Contributors: + * [ciniml](https://github.com/ciniml) + * [mongonta0716](https://github.com/mongonta0716) + * [tobozo](https://github.com/tobozo) + * /----------------------------------------------------------------------------*/ + +#if defined (ESP_PLATFORM) + +#include "Panel_NV3041A.hpp" +#include "../Bus.hpp" +#include "../platforms/common.hpp" +#include "../misc/pixelcopy.hpp" +#include "../misc/colortype.hpp" +#include "driver/spi_master.h" +#include "esp_log.h" + + +/** + * @brief Bug list (inherited from Panel_SH8601Z) + * + * > Write image (pushSprite) works fine, bugs down below are from writing directly + * + * 1> Write function is block even with DMA (manual CS wait data) + * 2> In spi 40MHz draw vertical line incomplete, but 10MHz OK (Likely because my dupont line connection) + * 3> After implement write/draw pixel funcs, "testFilledRects" stucks sometime, acts differently to the different sck freq + * 4> Haven't found the way to set rotation by reg + */ + + +namespace lgfx +{ + inline namespace v1 + { + //---------------------------------------------------------------------------- + + /* Panel init */ + bool Panel_NV3041A::init(bool use_reset) + { + // ESP_LOGD("NV3041A","pannel init %d", use_reset); + + if (!Panel_Device::init(use_reset)) { + return false; + } + + startWrite(); + cs_control(false); + write_cmd(CMD_SWRESET); + delay(150); + _bus->wait(); + cs_control(true); + endWrite(); + + startWrite(); + for(int i=0;iwrite_cmd(init_cmds[i]); + _bus->writeCommand(init_cmds[i+1], 8); + _bus->wait(); + cs_control(true); + delay(1); + } + endWrite(); + delay(120); + + startWrite(); + cs_control(false); + this->write_cmd(CMD_DISPON); + _bus->writeCommand(0x00, 8); + _bus->wait(); + cs_control(true); + endWrite(); + + return true; + } + + + void Panel_NV3041A::update_madctl(void) + { + uint8_t r = _internal_rotation; + switch (r) + { + case 1: + r = CMD_MADCTL_MY | CMD_MADCTL_MV | CMD_MADCTL_RGB; + break; + case 2: + r = CMD_MADCTL_RGB; + break; + case 3: + r = CMD_MADCTL_MX | CMD_MADCTL_MV | CMD_MADCTL_RGB; + break; + default: // case 0: + r = CMD_MADCTL_MX | CMD_MADCTL_MY | CMD_MADCTL_RGB; + break; + } + + startWrite(); + cs_control(false); + this->write_cmd(CMD_MADCTL); + _bus->writeCommand(r, 8); + _bus->wait(); + cs_control(true); + endWrite(); + } + + + + void Panel_NV3041A::setInvert(bool invert) + { + // ESP_LOGD("NV3041A","setInvert %d", invert); + + cs_control(false); + + if (invert) { + /* Inversion On */ + write_cmd(CMD_INVON); + } + else { + /* Inversion Off */ + write_cmd(CMD_INVOFF); + } + _bus->wait(); + + cs_control(true); + } + + + void Panel_NV3041A::setSleep(bool flg) + { + // ESP_LOGD("NV3041A","setSleep %d", flg); + + cs_control(false); + + if (flg) { + /* Sleep in */ + write_cmd(CMD_SLPIN); + } + else { + /* Sleep out */ + write_cmd(CMD_SLPOUT); + delay(150); + } + _bus->wait(); + + cs_control(true); + } + + + void Panel_NV3041A::setPowerSave(bool flg) + { + // ESP_LOGD("NV3041A","setPowerSave"); + } + + + void Panel_NV3041A::waitDisplay(void) + { + // ESP_LOGD("NV3041A","waitDisplay"); + } + + + bool Panel_NV3041A::displayBusy(void) + { + // ESP_LOGD("NV3041A","displayBusy"); + return false; + } + + + color_depth_t Panel_NV3041A::setColorDepth(color_depth_t depth) + { + // ESP_LOGD("NV3041A","setColorDepth %d", depth); + + /* 0x00: 16bit/pixel */ + /* 0x01: 18bit/pixel */ + uint8_t cmd_send = 0; + if (depth == rgb565_2Byte) { + cmd_send = 0x00; + } + else if (depth == rgb666_3Byte) { + cmd_send = 0x01; + } + else { + return _write_depth; + } + _write_depth = depth; + + /* Set interface Pixel Format */ + startWrite(); + + cs_control(false); + write_cmd(CMD_COLMOD); + _bus->writeCommand(cmd_send, 8); + _bus->wait(); + cs_control(true); + + endWrite(); + + return _write_depth; + } + + + void Panel_NV3041A::write_cmd(uint8_t cmd) + { + uint8_t cmd_buffer[4] = {0x02, 0x00, 0x00, 0x00}; + cmd_buffer[2] = cmd; + // _bus->writeBytes(cmd_buffer, 4, 0, false); + for (int i = 0; i < 4; i++) { + _bus->writeCommand(cmd_buffer[i], 8); + } + } + + + void Panel_NV3041A::start_qspi() + { + /* Begin QSPI */ + cs_control(false); + _bus->writeCommand(0x32, 8); + _bus->writeCommand(0x00, 8); + _bus->writeCommand(0x2C, 8); + _bus->writeCommand(0x00, 8); + _bus->wait(); + } + + void Panel_NV3041A::end_qspi() + { + /* Stop QSPI */ + _bus->writeCommand(0x32, 8); + _bus->writeCommand(0x00, 8); + _bus->writeCommand(0x00, 8); + _bus->writeCommand(0x00, 8); + _bus->wait(); + cs_control(true); + } + + + void Panel_NV3041A::beginTransaction(void) + { + // ESP_LOGD("NV3041A","beginTransaction"); + if (_in_transaction) return; + _in_transaction = true; + _bus->beginTransaction(); + } + + + void Panel_NV3041A::endTransaction(void) + { + // ESP_LOGD("NV3041A","endTransaction"); + // if (!_in_transaction) return; + // _in_transaction = false; + // _bus->endTransaction(); + + if (!_in_transaction) return; + _in_transaction = false; + + if (_has_align_data) + { + _has_align_data = false; + _bus->writeData(0, 8); + } + + _bus->endTransaction(); + } + + + void Panel_NV3041A::write_bytes(const uint8_t* data, uint32_t len, bool use_dma) + { + start_qspi(); + _bus->writeBytes(data, len, true, use_dma); + _bus->wait(); + end_qspi(); + } + + + void Panel_NV3041A::setWindow(uint_fast16_t xs, uint_fast16_t ys, uint_fast16_t xe, uint_fast16_t ye) + { + // ESP_LOGD("NV3041A","setWindow %d %d %d %d", xs, ys, xe, ye); + + /* Set limit */ + if ((xe - xs) >= _width) { xs = 0; xe = _width - 1; } + if ((ye - ys) >= _height) { ys = 0; ye = _height - 1; } + + /* Set Column Start Address */ + cs_control(false); + write_cmd(CMD_CASET); + _bus->writeCommand(xs >> 8, 8); + _bus->writeCommand(xs & 0xFF, 8); + _bus->writeCommand(xe >> 8, 8); + _bus->writeCommand(xe & 0xFF, 8); + _bus->wait(); + cs_control(true); + + /* Set Row Start Address */ + cs_control(false); + write_cmd(CMD_RASET); + _bus->writeCommand(ys >> 8, 8); + _bus->writeCommand(ys & 0xFF, 8); + _bus->writeCommand(ye >> 8, 8); + _bus->writeCommand(ye & 0xFF, 8); + _bus->wait(); + cs_control(true); + + /* Memory Write */ + cs_control(false); + write_cmd(CMD_RAMWR); + _bus->wait(); + cs_control(true); + } + + + void Panel_NV3041A::writeBlock(uint32_t rawcolor, uint32_t len) + { + // ESP_LOGD("NV3041A","writeBlock 0x%lx %ld", rawcolor, len); + + /* Push color */ + start_qspi(); + _bus->writeDataRepeat(rawcolor, _write_bits, len); + _bus->wait(); + end_qspi(); + } + + + + + void Panel_NV3041A::writePixels(pixelcopy_t* param, uint32_t len, bool use_dma) + { + // ESP_LOGD("NV3041A","writePixels %ld %d", len, use_dma); + + start_qspi(); + + if (param->no_convert) { + _bus->writeBytes(reinterpret_cast(param->src_data), len * _write_bits >> 3, true, use_dma); + } + else { + _bus->writePixels(param, len); + } + if (_cfg.dlen_16bit && (_write_bits & 15) && (len & 1)) { + _has_align_data = !_has_align_data; + } + + _bus->wait(); + end_qspi(); + } + + + void Panel_NV3041A::drawPixelPreclipped(uint_fast16_t x, uint_fast16_t y, uint32_t rawcolor) + { + // ESP_LOGD("NV3041A","drawPixelPreclipped %d %d 0x%lX", x, y, rawcolor); + + setWindow(x,y,x,y); + if (_cfg.dlen_16bit) { _has_align_data = (_write_bits & 15); } + + start_qspi(); + + _bus->writeData(rawcolor, _write_bits); + + _bus->wait(); + end_qspi(); + } + + + void Panel_NV3041A::writeFillRectPreclipped(uint_fast16_t x, uint_fast16_t y, uint_fast16_t w, uint_fast16_t h, uint32_t rawcolor) + { + // ESP_LOGD("NV3041A","writeFillRectPreclipped %d %d %d %d 0x%lX", x, y, w, h, rawcolor); + + uint32_t len = w * h; + uint_fast16_t xe = w + x - 1; + uint_fast16_t ye = y + h - 1; + + setWindow(x,y,xe,ye); + // if (_cfg.dlen_16bit) { _has_align_data = (_write_bits & 15) && (len & 1); } + + start_qspi(); + _bus->writeDataRepeat(rawcolor, _write_bits, len); + _bus->wait(); + end_qspi(); + } + + + + void Panel_NV3041A::writeImage(uint_fast16_t x, uint_fast16_t y, uint_fast16_t w, uint_fast16_t h, pixelcopy_t* param, bool use_dma) + { + // ESP_LOGD("NV3041A","writeImage %d %d %d %d %d", x, y, w, h, use_dma); + // use_dma = false; + + auto bytes = param->dst_bits >> 3; + auto src_x = param->src_x; + + if (param->transp == pixelcopy_t::NON_TRANSP) + { + if (param->no_convert) + { + auto wb = w * bytes; + uint32_t i = (src_x + param->src_y * param->src_bitwidth) * bytes; + auto src = &((const uint8_t*)param->src_data)[i]; + setWindow(x, y, x + w - 1, y + h - 1); + if (param->src_bitwidth == w || h == 1) + { + write_bytes(src, wb * h, use_dma); + } + else + { + auto add = param->src_bitwidth * bytes; + if (use_dma) + { + if (_cfg.dlen_16bit && ((wb * h) & 1)) + { + _has_align_data = !_has_align_data; + } + do + { + _bus->addDMAQueue(src, wb); + src += add; + } while (--h); + _bus->execDMAQueue(); + } + else + { + do + { + write_bytes(src, wb, false); + src += add; + } while (--h); + } + } + } + else + { + if (!_bus->busy()) + { + static constexpr uint32_t WRITEPIXELS_MAXLEN = 32767; + + setWindow(x, y, x + w - 1, y + h - 1); + // bool nogap = (param->src_bitwidth == w || h == 1); + bool nogap = (h == 1) || (param->src_y32_add == 0 && ((param->src_bitwidth << pixelcopy_t::FP_SCALE) == (w * param->src_x32_add))); + if (nogap && (w * h <= WRITEPIXELS_MAXLEN)) + { + writePixels(param, w * h, use_dma); + } + else + { + uint_fast16_t h_step = nogap ? WRITEPIXELS_MAXLEN / w : 1; + uint_fast16_t h_len = (h_step > 1) ? ((h - 1) % h_step) + 1 : 1; + writePixels(param, w * h_len, use_dma); + if (h -= h_len) + { + param->src_y += h_len; + do + { + param->src_x = src_x; + writePixels(param, w * h_step, use_dma); + param->src_y += h_step; + } while (h -= h_step); + } + } + } + else + { + size_t wb = w * bytes; + auto buf = _bus->getDMABuffer(wb); + param->fp_copy(buf, 0, w, param); + setWindow(x, y, x + w - 1, y + h - 1); + write_bytes(buf, wb, true); + _has_align_data = (_cfg.dlen_16bit && (_write_bits & 15) && (w & h & 1)); + while (--h) + { + param->src_x = src_x; + param->src_y++; + buf = _bus->getDMABuffer(wb); + param->fp_copy(buf, 0, w, param); + write_bytes(buf, wb, true); + } + } + } + } + else + { + h += y; + uint32_t wb = w * bytes; + do + { + uint32_t i = 0; + while (w != (i = param->fp_skip(i, w, param))) + { + auto buf = _bus->getDMABuffer(wb); + int32_t len = param->fp_copy(buf, 0, w - i, param); + setWindow(x + i, y, x + i + len - 1, y); + write_bytes(buf, len * bytes, true); + if (w == (i += len)) break; + } + param->src_x = src_x; + param->src_y++; + } while (++y != h); + } + } + + + + + uint32_t Panel_NV3041A::readCommand(uint_fast16_t cmd, uint_fast8_t index, uint_fast8_t len) + { + // ESP_LOGD("NV3041A","readCommand"); + return 0; + } + + uint32_t Panel_NV3041A::readData(uint_fast8_t index, uint_fast8_t len) + { + // ESP_LOGD("NV3041A","readData"); + return 0; + } + + void Panel_NV3041A::readRect(uint_fast16_t x, uint_fast16_t y, uint_fast16_t w, uint_fast16_t h, void* dst, pixelcopy_t* param) + { + // ESP_LOGD("NV3041A","readRect"); + } + + + //---------------------------------------------------------------------------- + } +} + + +#endif diff --git a/src/lgfx/v1/panel/Panel_NV3041A.hpp b/src/lgfx/v1/panel/Panel_NV3041A.hpp new file mode 100644 index 00000000..721678f4 --- /dev/null +++ b/src/lgfx/v1/panel/Panel_NV3041A.hpp @@ -0,0 +1,205 @@ +/*----------------------------------------------------------------------------/ + * Lovyan GFX - Graphics library for embedded devices. + * + * Original Source: + * https://github.com/lovyan03/LovyanGFX/ + * + * Licence: + * [FreeBSD](https://github.com/lovyan03/LovyanGFX/blob/master/license.txt) + * + * Author: + * [lovyan03](https://twitter.com/lovyan03) + * + * Contributors: + * [ciniml](https://github.com/ciniml) + * [mongonta0716](https://github.com/mongonta0716) + * [tobozo](https://github.com/tobozo) + * /----------------------------------------------------------------------------*/ +#pragma once + +#if defined (ESP_PLATFORM) + +#include "Panel_LCD.hpp" + + +namespace lgfx +{ + inline namespace v1 + { + //---------------------------------------------------------------------------- + + struct Panel_NV3041A : public Panel_LCD + { + protected: + + static constexpr uint8_t CMD_RST_DELAY = 120 ; ///< delay ms wait for reset finish + static constexpr uint8_t CMD_SLPIN_DELAY = 120 ; ///< delay ms wait for sleep in finish + static constexpr uint8_t CMD_SLPOUT_DELAY = 120 ; ///< delay ms wait for sleep out finish + static constexpr uint8_t CMD_NOP = 0x00; + static constexpr uint8_t CMD_SWRESET = 0x01; + static constexpr uint8_t CMD_SLPIN = 0x10; + static constexpr uint8_t CMD_SLPOUT = 0x11; + static constexpr uint8_t CMD_INVOFF = 0x20; + static constexpr uint8_t CMD_INVON = 0x21; + static constexpr uint8_t CMD_DISPOFF = 0x28; + static constexpr uint8_t CMD_DISPON = 0x29; + static constexpr uint8_t CMD_CASET = 0x2A; + static constexpr uint8_t CMD_RASET = 0x2B; + static constexpr uint8_t CMD_RAMWR = 0x2C; + static constexpr uint8_t CMD_MADCTL = 0x36; + static constexpr uint8_t CMD_COLMOD = 0x3A; + static constexpr uint8_t CMD_GATEON = 0x51; + static constexpr uint8_t CMD_MADCTL_MY = 0x80; + static constexpr uint8_t CMD_MADCTL_MX = 0x40; + static constexpr uint8_t CMD_MADCTL_MV = 0x20; + static constexpr uint8_t CMD_MADCTL_ML = 0x10; + static constexpr uint8_t CMD_MADCTL_RGB = 0x0 ; + + + static constexpr uint8_t init_cmds[91*2] = + { + // init sequence grabbed from Arduino_GFX (kudos to @moononournation) + // 91 pairs, delay after = 120 + 0xff, 0xa5, + 0x36, 0xc0, + 0x3A, 0x01, // 01---565,00---666 + 0x41, 0x03, // 01--8bit, 03-16bit + 0x44, 0x15, // VBP ????? 21 + 0x45, 0x15, // VFP ????? 21 + 0x7d, 0x03, // vdds_trim[2:0] + 0xc1, 0xbb, // avdd_clp_en avdd_clp[1:0] avcl_clp_en avcl_clp[1:0], 0xbb 88 a2 + 0xc2, 0x05, // vgl_clp_en vgl_clp[2:0] + 0xc3, 0x10, // vgl_clp_en vgl_clp[2:0] + 0xc6, 0x3e, // avdd_ratio_sel avcl_ratio_sel vgh_ratio_sel[1:0] vgl_ratio_sel[1:0] = 35 + 0xc7, 0x25, // mv_clk_sel[1:0] avdd_clk_sel[1:0] avcl_clk_sel[1:0] = 2e + 0xc8, 0x11, // VGL_CLK_sel + 0x7a, 0x5f, // user_vgsp .. 4f:0.8V 3f:1.04V 5f + 0x6f, 0x44, // user_gvdd .. 1C:5.61 5f 53 2a 3a + 0x78, 0x70, // user_gvcl .. 50:-3.22 75 58 66 + 0xc9, 0x00, + 0x67, 0x21, + 0x51, 0x0a, // gate_st_o[7:0] + 0x52, 0x76, // gate_ed_o[7:0] .. 76 + 0x53, 0x0a, // gate_st_e[7:0] .. 76 + 0x54, 0x76, // gate_ed_e[7:0] + 0x46, 0x0a, // fsm_hbp_o[5:0] + 0x47, 0x2a, // fsm_hfp_o[5:0] + 0x48, 0x0a, // fsm_hbp_e[5:0] + 0x49, 0x1a, // fsm_hfp_e[5:0] + 0x56, 0x43, // src_ld_wd[1:0] src_ld_st[5:0] + 0x57, 0x42, // pn_cs_en src_cs_st[5:0] + 0x58, 0x3c, // src_cs_p_wd[6:0] + 0x59, 0x64, // src_cs_n_wd[6:0] + 0x5a, 0x41, // src_pchg_st_o[6:0] .. 41 + 0x5b, 0x3c, // src_pchg_wd_o[6:0] + 0x5c, 0x02, // src_pchg_st_e[6:0] .. 02 + 0x5d, 0x3c, // src_pchg_wd_e[6:0] .. 3c + 0x5e, 0x1f, // src_pol_sw[7:0] + 0x60, 0x80, // src_op_st_o[7:0] + 0x61, 0x3f, // src_op_st_e[7:0] + 0x62, 0x21, // src_op_ed_o[9:8] src_op_ed_e[9:8] + 0x63, 0x07, // src_op_ed_o[7:0] + 0x64, 0xe0, // src_op_ed_e[7:0] + 0x65, 0x02, // chopper + 0xca, 0x20, // avdd_mux_st_o[7:0] + 0xcb, 0x52, // avdd_mux_ed_o[7:0] .. 52 + 0xcc, 0x10, // avdd_mux_st_e[7:0] + 0xcD, 0x42, // avdd_mux_ed_e[7:0] + 0xD0, 0x20, // avcl_mux_st_o[7:0] + 0xD1, 0x52, // avcl_mux_ed_o[7:0] + 0xD2, 0x10, // avcl_mux_st_e[7:0] + 0xD3, 0x42, // avcl_mux_ed_e[7:0] + 0xD4, 0x0a, // vgh_mux_st[7:0] + 0xD5, 0x32, // vgh_mux_ed[7:0] + ////gammma weihuan pianguangpian 0913 + 0x80, 0x00, // gam_vrp0 0 6bit + 0xA0, 0x00, // gam_VRN0 0- + 0x81, 0x07, // gam_vrp1 1 6bit + 0xA1, 0x06, // gam_VRN1 1- + 0x82, 0x02, // gam_vrp2 2 6bit + 0xA2, 0x01, // gam_VRN2 2- + 0x86, 0x11, // gam_prp0 7bit 8 7bit .. 33 + 0xA6, 0x10, // gam_PRN0 8- .. 2a + 0x87, 0x27, // gam_prp1 7bit 40 7bit .. 2d + 0xA7, 0x27, // gam_PRN1 40- .. 2d + 0x83, 0x37, // gam_vrp3 61 6bit + 0xA3, 0x37, // gam_VRN3 61- + 0x84, 0x35, // gam_vrp4 62 6bit + 0xA4, 0x35, // gam_VRN4 62- + 0x85, 0x3f, // gam_vrp5 63 6bit + 0xA5, 0x3f, // gam_VRN5 63- + 0x88, 0x0b, // gam_pkp0 4 5bit .. 0b + 0xA8, 0x0b, // gam_PKN0 4- .. 0b + 0x89, 0x14, // gam_pkp1 5 5bit .. 14 + 0xA9, 0x14, // gam_PKN1 5- .. 14 + 0x8a, 0x1a, // gam_pkp2 7 5bit .. 1a + 0xAa, 0x1a, // gam_PKN2 7- .. 1a + 0x8b, 0x0a, // gam_PKP3 10 5bit + 0xAb, 0x0a, // gam_PKN3 10- + 0x8c, 0x14, // gam_PKP4 16 5bit + 0xAc, 0x08, // gam_PKN4 16- + 0x8d, 0x17, // gam_PKP5 22 5bit + 0xAd, 0x07, // gam_PKN5 22- + 0x8e, 0x16, // gam_PKP6 28 5bit .. 16 change + 0xAe, 0x06, // gam_PKN6 28- .. 13change + 0x8f, 0x1B, // gam_PKP7 34 5bit + 0xAf, 0x07, // gam_PKN7 34- + 0x90, 0x04, // gam_PKP8 46 5bit + 0xB0, 0x04, // gam_PKN8 46- + 0x91, 0x0A, // gam_PKP9 52 5bit + 0xB1, 0x0A, // gam_PKN9 52- + 0x92, 0x16, // gam_PKP10 58 5bit + 0xB2, 0x15, // gam_PKN10 58- + 0xff, 0x00, + 0x11, 0x00, + + }; + + public: + Panel_NV3041A(void) + { + _cfg.memory_width = _cfg.panel_width = 480; + _cfg.memory_height = _cfg.panel_height = 272; + } + + bool init(bool use_reset) override; + void beginTransaction(void) override; + void endTransaction(void) override; + + color_depth_t setColorDepth(color_depth_t depth) override; + //void setRotation(uint_fast8_t r) override; + void setInvert(bool invert) override; + void setSleep(bool flg) override; + void setPowerSave(bool flg) override; + + void waitDisplay(void) override; + bool displayBusy(void) override; + + void writePixels(pixelcopy_t* param, uint32_t len, bool use_dma) override; + void writeBlock(uint32_t rawcolor, uint32_t len) override; + + void setWindow(uint_fast16_t xs, uint_fast16_t ys, uint_fast16_t xe, uint_fast16_t ye) override; + void drawPixelPreclipped(uint_fast16_t x, uint_fast16_t y, uint32_t rawcolor) override; + void writeFillRectPreclipped(uint_fast16_t x, uint_fast16_t y, uint_fast16_t w, uint_fast16_t h, uint32_t rawcolor) override; + void writeImage(uint_fast16_t x, uint_fast16_t y, uint_fast16_t w, uint_fast16_t h, pixelcopy_t* param, bool use_dma) override; + + uint32_t readCommand(uint_fast16_t cmd, uint_fast8_t index, uint_fast8_t len) override; + uint32_t readData(uint_fast8_t index, uint_fast8_t len) override; + void readRect(uint_fast16_t x, uint_fast16_t y, uint_fast16_t w, uint_fast16_t h, void* dst, pixelcopy_t* param) override; + + protected: + bool _in_transaction = false; + + void update_madctl(void); + void write_cmd(uint8_t cmd); + void start_qspi(); + void end_qspi(); + void write_bytes(const uint8_t* data, uint32_t len, bool use_dma); + }; + + //---------------------------------------------------------------------------- + } +} + + +#endif diff --git a/src/lgfx/v1/panel/Panel_SH8601Z.cpp b/src/lgfx/v1/panel/Panel_SH8601Z.cpp index f154956d..292871c9 100644 --- a/src/lgfx/v1/panel/Panel_SH8601Z.cpp +++ b/src/lgfx/v1/panel/Panel_SH8601Z.cpp @@ -45,6 +45,8 @@ namespace lgfx { //---------------------------------------------------------------------------- + + /* Panel init */ bool Panel_SH8601Z::init(bool use_reset) { @@ -55,75 +57,20 @@ namespace lgfx } - /* Store pannel resolution */ - _width = _cfg.panel_width; - _height = _cfg.panel_height; - - - startWrite(); - - /* Sleep out */ - cs_control(false); - write_cmd(0x11); - _bus->wait(); - cs_control(true); - delay(150); - - cs_control(false); - write_cmd(0x44); - _bus->writeCommand(0x01, 8); - _bus->writeCommand(0x66, 8); - _bus->wait(); - cs_control(true); - delay(1); - - /* TE on */ - cs_control(false); - write_cmd(0x35); - _bus->writeCommand(0x00, 8); - _bus->wait(); - cs_control(true); - delay(1); - - /* Interface Pixel Format 16bit/pixel */ - cs_control(false); - write_cmd(0x3A); - _bus->writeCommand(0x55, 8); - _bus->wait(); - cs_control(true); - delay(1); - - cs_control(false); - write_cmd(0x53); - _bus->writeCommand(0x20, 8); - _bus->wait(); - cs_control(true); - delay(10); - - /* Write Display Brightness MAX_VAL=0XFF */ - cs_control(false); - write_cmd(0x51); - _bus->writeCommand(0x00, 8); - _bus->wait(); - cs_control(true); - delay(10); - - /* Display on */ - cs_control(false); - write_cmd(0x29); - _bus->wait(); - cs_control(true); - delay(10); - - /* Write Display Brightness MAX_VAL=0XFF */ - cs_control(false); - write_cmd(0x51); - _bus->writeCommand(0xFF, 8); - _bus->wait(); - cs_control(true); - delay(1); - - endWrite(); + uint8_t cmds[] = + { + 0x11, 0+CMD_INIT_DELAY, 150, // Sleep out + 0x44, 2+CMD_INIT_DELAY, 0x01, 0x66, 1, + 0x35, 1+CMD_INIT_DELAY, 0x00, 1, // TE on + 0x3a, 1+CMD_INIT_DELAY, 0x55, 1, // Interface Pixel Format 16bit/pixel + 0x53, 1+CMD_INIT_DELAY, 0x20, 10, + 0x51, 1+CMD_INIT_DELAY, 0x00, 10, // Write Display Brightness MAX_VAL=0XFF + 0x29, 0+CMD_INIT_DELAY, 10, + 0x51, 1+CMD_INIT_DELAY, 0xff, 1, // Write Display Brightness MAX_VAL=0XFF + 0xff, 0xff + }; + + this->command_list(cmds); return true; } @@ -279,6 +226,41 @@ namespace lgfx } + void Panel_SH8601Z::command_list(const uint8_t *addr) + { + startWrite(); + for (;;) + { // For each command... + uint8_t cmd = *addr++; + uint8_t num = *addr++; // Number of args to follow + if (cmd == 0xFF && num == 0xFF) break; + + cs_control(false); + + this->write_cmd(cmd); // Read, issue command + uint_fast8_t ms = num & CMD_INIT_DELAY; // If hibit set, delay follows args + num &= ~CMD_INIT_DELAY; // Mask out delay bit + if (num) + { + do + { // For each argument... + _bus->writeCommand(*addr++, 8); + } while (--num); + } + + _bus->wait(); + cs_control(true); + + if (ms) + { + ms = *addr++; // Read post-command delay time (ms) + delay( (ms==255 ? 500 : ms) ); + } + } + endWrite(); + } + + void Panel_SH8601Z::write_cmd(uint8_t cmd) { uint8_t cmd_buffer[4] = {0x02, 0x00, 0x00, 0x00}; diff --git a/src/lgfx/v1/panel/Panel_SH8601Z.hpp b/src/lgfx/v1/panel/Panel_SH8601Z.hpp index bdc631b0..e9b0e3d2 100644 --- a/src/lgfx/v1/panel/Panel_SH8601Z.hpp +++ b/src/lgfx/v1/panel/Panel_SH8601Z.hpp @@ -64,6 +64,8 @@ namespace lgfx protected: bool _in_transaction = false; + void command_list(const uint8_t *addr); + void write_cmd(uint8_t cmd); void start_qspi(); void end_qspi(); diff --git a/src/lgfx_user/LGFX_JC4827W543_4.3inch_ESP32S3.hpp b/src/lgfx_user/LGFX_JC4827W543_4.3inch_ESP32S3.hpp new file mode 100644 index 00000000..a8dc0936 --- /dev/null +++ b/src/lgfx_user/LGFX_JC4827W543_4.3inch_ESP32S3.hpp @@ -0,0 +1,112 @@ +/** + * @file LGFX_JC4827W543_4.3inch_ESP32S3.hpp + * @author tobozo + * @brief + * @version 0.1 + * @date 2024-08-21 + * + * @copyleft Copyleft (c+) tobozo 2024 + * + */ +#pragma once +#include +#include + +class LGFX : public lgfx::LGFX_Device { + + lgfx::Touch_GT911 _touch_instance; + lgfx::Panel_NV3041A _panel_instance; + lgfx::Bus_QSPI _bus_instance; + lgfx::Light_PWM _light_instance; + +public: + + LGFX(void) + { + { + auto cfg = _bus_instance.config(); + + cfg.spi_host = SPI3_HOST; + cfg.spi_mode = 1; + cfg.freq_write = 32000000UL; // NV3041A Maximum supported speed is 32MHz + cfg.freq_read = 16000000; + cfg.spi_3wire = true; + cfg.use_lock = true; + cfg.dma_channel = SPI_DMA_CH_AUTO; + + cfg.pin_sclk = GPIO_NUM_47; + cfg.pin_io0 = GPIO_NUM_21; + cfg.pin_io1 = GPIO_NUM_48; + cfg.pin_io2 = GPIO_NUM_40; + cfg.pin_io3 = GPIO_NUM_39; + + _bus_instance.config(cfg); + _panel_instance.setBus(&_bus_instance); + } + + + { + auto cfg = _panel_instance.config(); + + cfg.pin_cs = GPIO_NUM_45; // Chip select pin + cfg.pin_rst = GPIO_NUM_4 ; // Reset pin + cfg.pin_busy = -1; // Busy pin (not used) + + cfg.panel_width = 480; + cfg.panel_height = 272; + + cfg.memory_width = 480; + cfg.memory_height = 272; + + cfg.offset_x = 0; + cfg.offset_y = 0; + + cfg.offset_rotation = 0; + + cfg.dummy_read_pixel = 8; + cfg.dummy_read_bits = 1; + + cfg.readable = true; + cfg.invert = true; + cfg.rgb_order = true; + cfg.dlen_16bit = false; + cfg.bus_shared = true; + + _panel_instance.config(cfg); + } + + { // Configure settings for touch screen control. (delete if not necessary) + auto cfg = _touch_instance.config(); + + cfg.x_min = 0; + cfg.x_max = 480 - 1; + cfg.y_min = 0; + cfg.y_max = 272 - 1; + cfg.offset_rotation = 6; // 6 fits but double lines. why? + + // For SPI connection + cfg.bus_shared = false; // Set true when using a common bus with the screen + cfg.spi_host = SPI2_HOST; // Select SPI to use (HSPI_HOST or VSPI_HOST) + cfg.freq = 2500000; // SPI Clock frequency 1000000 -> 2500000 + cfg.pin_int = -1; // Pin number to which INT is connected (-1 = not connected) + cfg.pin_sda = GPIO_NUM_8 ; // SCLK + cfg.pin_scl = GPIO_NUM_4 ; // CS + + _touch_instance.config(cfg); + _panel_instance.setTouch(&_touch_instance); + } + + { + auto cfg = _light_instance.config(); + + cfg.pin_bl = GPIO_NUM_1 ; // Backlight pin + cfg.invert = false; + + _light_instance.config(cfg); + _panel_instance.setLight(&_light_instance); + } + + setPanel(&_panel_instance); + } + +};