diff esp/update_lcd_block.h @ 8:47795c3121f1

bufferless updates! mqtt message is sent over SPI and everything works
author drewp@bigasterisk.com
date Mon, 11 Mar 2024 01:37:57 -0700
parents b46679798c51
children
line wrap: on
line diff
--- a/esp/update_lcd_block.h	Sun Mar 10 15:03:53 2024 -0700
+++ b/esp/update_lcd_block.h	Mon Mar 11 01:37:57 2024 -0700
@@ -1,16 +1,270 @@
 #include <string>
 
 #include "esphome.h"
-#include "esphome/components/ili9xxx/ili9xxx_display.h"
-void update_lcd_block(esphome::ili9xxx::ILI9XXXDisplay *lcd, std::string &x) {
-  id(lcd).update();
+// some from esphome; other code from
+// https://github.com/lvgl/lvgl_esp32_drivers/blob/master/lvgl_tft/ili9481.c
+// #include "esphome/components/ili9xxx/ili9xxx_display.h"
+
+static const char *const TAG = "ili9481direct";
+
+namespace esphome {
+namespace ili9xxx {
+
+/* MIPI DCS Type1  */
+#define ILI9481_CMD_NOP 0x00
+#define ILI9481_CMD_SOFTWARE_RESET 0x01
+#define ILI9481_CMD_READ_DISP_POWER_MODE 0x0A
+#define ILI9481_CMD_READ_DISP_MADCTRL 0x0B  // bits 7:3 only
+#define ILI9481_CMD_READ_DISP_PIXEL_FORMAT 0x0C
+#define ILI9481_CMD_READ_DISP_IMAGE_MODE 0x0D
+#define ILI9481_CMD_READ_DISP_SIGNAL_MODE 0x0E
+#define ILI9481_CMD_READ_DISP_SELF_DIAGNOSTIC 0x0F  // bits 7:6 only
+#define ILI9481_CMD_ENTER_SLEEP_MODE 0x10
+#define ILI9481_CMD_SLEEP_OUT 0x11
+#define ILI9481_CMD_PARTIAL_MODE_ON 0x12
+#define ILI9481_CMD_NORMAL_DISP_MODE_ON 0x13
+#define ILI9481_CMD_DISP_INVERSION_OFF 0x20
+#define ILI9481_CMD_DISP_INVERSION_ON 0x21
+#define ILI9481_CMD_DISPLAY_OFF 0x28
+#define ILI9481_CMD_DISPLAY_ON 0x29
+#define ILI9481_CMD_COLUMN_ADDRESS_SET 0x2A
+#define ILI9481_CMD_PAGE_ADDRESS_SET 0x2B
+#define ILI9481_CMD_MEMORY_WRITE 0x2C
+#define ILI9481_CMD_MEMORY_READ 0x2E
+#define ILI9481_CMD_PARTIAL_AREA 0x30
+#define ILI9481_CMD_VERT_SCROLL_DEFINITION 0x33
+#define ILI9481_CMD_TEARING_EFFECT_LINE_OFF 0x34
+#define ILI9481_CMD_TEARING_EFFECT_LINE_ON 0x35
+#define ILI9481_CMD_MEMORY_ACCESS_CONTROL 0x36  // bits 7:3,1:0 only
+#define ILI9481_CMD_VERT_SCROLL_START_ADDRESS 0x37
+#define ILI9481_CMD_IDLE_MODE_OFF 0x38
+#define ILI9481_CMD_IDLE_MODE_ON 0x39
+#define ILI9481_CMD_COLMOD_PIXEL_FORMAT_SET 0x3A
+#define ILI9481_CMD_WRITE_MEMORY_CONTINUE 0x3C
+#define ILI9481_CMD_READ_MEMORY_CONTINUE 0x3E
+#define ILI9481_CMD_SET_TEAR_SCANLINE 0x44
+#define ILI9481_CMD_GET_SCANLINE 0x45
+
+#define ILI9481_DDB_START 0xA1
+#define ILI9481_DDB_CONTINUE 0xA8
+
+/* other */
+#define ILI9481_CMD_ACCESS_PROTECT 0xB0
+#define ILI9481_CMD_LOW_POWER_CONTROL 0xB1
+#define ILI9481_CMD_FRAME_MEMORY_ACCESS 0xB3
+#define ILI9481_CMD_DISPLAY_MODE 0xB4
+#define ILI9481_CMD_DEVICE_CODE 0xBF
+
+#define ILI9481_CMD_PANEL_DRIVE 0xC0
+#define ILI9481_CMD_DISP_TIMING_NORMAL 0xC1
+#define ILI9481_CMD_DISP_TIMING_PARTIAL 0xC2
+#define ILI9481_CMD_DISP_TIMING_IDLE 0xC3
+#define ILI9481_CMD_FRAME_RATE 0xC5
+#define ILI9481_CMD_INTERFACE_CONTROL 0xC6
+#define ILI9481_CMD_GAMMA_SETTING 0xC8
+
+#define ILI9481_CMD_POWER_SETTING 0xD0
+#define ILI9481_CMD_VCOM_CONTROL 0xD1
+#define ILI9481_CMD_POWER_CONTROL_NORMAL 0xD2
+#define ILI9481_CMD_POWER_CONTROL_IDEL 0xD3
+#define ILI9481_CMD_POWER_CONTROL_PARTIAL 0xD4
+
+#define ILI9481_CMD_NVMEM_WRITE 0xE0
+#define ILI9481_CMD_NVMEM_PROTECTION_KEY 0xE1
+#define ILI9481_CMD_NVMEM_STATUS_READ 0xE2
+#define ILI9481_CMD_NVMEM_PROTECTION 0xE3
+
+typedef struct {
+  uint8_t cmd;
+  uint8_t data[16];
+  uint8_t databytes;  // No of data in data; bit 7 = delay after set; 0xFF = end
+                      // of cmds.
+} lcd_init_cmd_t;
+
+lcd_init_cmd_t ili_init_cmds[] = {
+    {ILI9481_CMD_SLEEP_OUT, {0x00}, 0x80},
+
+    // {ILI9481_CMD_POWER_SETTING, {0x07, 0x42, 0x18}, 3},  // from lvgl code
+    {ILI9481_CMD_POWER_SETTING, {0x07, 0x41, 0x1D}, 3},  // from esphome code
+
+    // {ILI9481_CMD_VCOM_CONTROL, {0x00, 0x07, 0x10}, 3},  // from lvgl code
+    {ILI9481_CMD_VCOM_CONTROL, {0x00, 0x1c, 0x1f}, 3},  // from esphome code
+
+    // {ILI9481_CMD_POWER_CONTROL_NORMAL, {0x01, 0x02}, 2},  // from lvgl code
+    {ILI9481_CMD_POWER_CONTROL_NORMAL, {0x01, 0x11}, 2},  // from esphome code
+
+    {ILI9481_CMD_PANEL_DRIVE, {0x10, 0x3B, 0x00, 0x02, 0x11}, 5},
+    {ILI9481_CMD_FRAME_RATE, {0x03}, 1},
+    {ILI9481_CMD_FRAME_MEMORY_ACCESS, {0x0, 0x0, 0x0, 0x0}, 4},
+    //{ILI9481_CMD_DISP_TIMING_NORMAL, {0x10, 0x10, 0x22}, 3},
+    {ILI9481_CMD_GAMMA_SETTING,
+     {0x00, 0x32, 0x36, 0x45, 0x06, 0x16, 0x37, 0x75, 0x77, 0x54, 0x0C, 0x00},
+     12},
+
+#define ILI9481_ADDR_PAGE_ADDR_ORDER_B_TO_T 0x80
+#define ILI9481_ADDR_COL_ADDR_ORDER_R_TO_L 0x40
+#define ILI9481_ADDR_PAGE_COLUMN_ORDER_REVERSE 0x20
+#define ILI9481_ADDR_LCD_REFRESH_BOT_TO_TOP 0x10
+#define ILI9481_ADDR_BGR_ORDER 0x08
+#define ILI9481_ADDR_HFLIP 0x02
+#define ILI9481_ADDR_VFLIP 0x01
+
+    {ILI9481_CMD_MEMORY_ACCESS_CONTROL,
+     {ILI9481_ADDR_BGR_ORDER |
+      ILI9481_ADDR_HFLIP |
+      0},
+     1},
+
+    {ILI9481_CMD_COLMOD_PIXEL_FORMAT_SET, {0x66}, 1},
+    // {ILI9481_CMD_COLMOD_PIXEL_FORMAT_SET, {0x55}, 1},
+
+    {ILI9481_CMD_DISP_INVERSION_ON, {}, 0x80},
+    {ILI9481_CMD_NORMAL_DISP_MODE_ON, {}, 0x80},
+    {ILI9481_CMD_DISPLAY_ON, {}, 0x80},
+    {0, {0}, 0xff},
+};
 
-#if 1
-          std::string localPayload = x;
-          const char *buf = localPayload.data();
+class ILI9481Direct
+    : public Component,
+      public spi::SPIDevice<spi::BIT_ORDER_MSB_FIRST, spi::CLOCK_POLARITY_LOW,
+                            spi::CLOCK_PHASE_LEADING,
+                            // spi::DATA_RATE_40MHZ
+                            spi::DATA_RATE_10MHZ> {
+ public:
+  ILI9481Direct(esphome::spi::SPIComponent *spi) { spi_ = spi; }
+  esphome::spi::SPIComponent *spi_;
+  int width_ = 320;
+  int height_ = 480;
+  esp32::ESP32InternalGPIOPin *reset_pin_;
+  esp32::ESP32InternalGPIOPin *dc_pin_;
+  esp32::ESP32InternalGPIOPin *cs_pin_;
+
+  void setup() override {
+    this->setup_pins_();
+    this->init_lcd_();
+  }
+  void loop() override {}
+
+  void setup_pins_() {
+    dc_pin_ = new esp32::ESP32InternalGPIOPin();
+    dc_pin_->set_pin(::GPIO_NUM_22);
+    dc_pin_->set_inverted(false);
+    dc_pin_->set_drive_strength(::GPIO_DRIVE_CAP_2);
+    dc_pin_->set_flags(gpio::Flags::FLAG_OUTPUT);
+
+    dc_pin_->setup();  // OUTPUT
+    dc_pin_->digital_write(false);
+
+    reset_pin_ = new esp32::ESP32InternalGPIOPin();
+    reset_pin_->set_pin(::GPIO_NUM_25);
+    reset_pin_->set_inverted(false);
+    reset_pin_->set_drive_strength(::GPIO_DRIVE_CAP_2);
+    reset_pin_->set_flags(gpio::Flags::FLAG_OUTPUT);
+
+    reset_pin_->setup();  // OUTPUT
+    reset_pin_->digital_write(true);
+
+    cs_pin_ = new esp32::ESP32InternalGPIOPin();
+    cs_pin_->set_pin(::GPIO_NUM_27);
+    cs_pin_->set_inverted(false);
+    cs_pin_->set_drive_strength(::GPIO_DRIVE_CAP_2);
+    cs_pin_->set_flags(gpio::Flags::FLAG_OUTPUT);
+
+    set_cs_pin(cs_pin_);
+    set_spi_parent(spi_);
+    spi_setup();
+    reset_();
+  }
+
+  void init_lcd_() {
+    command(ILI9481_CMD_SOFTWARE_RESET);
+    delay(150);
+
+    uint16_t cmd = 0;
+    while (ili_init_cmds[cmd].databytes != 0xff) {
+      command(ili_init_cmds[cmd].cmd);
+      {
+        start_data_();
+        write_array(ili_init_cmds[cmd].data,
+                    ili_init_cmds[cmd].databytes & 0x1F);
+        end_data_();
+      }
+      if (ili_init_cmds[cmd].databytes & 0x80) {
+        delay(150);
+      }
+      cmd++;
+    }
+    ESP_LOGI(TAG, "done init cmds");
+  }
+
+  void blit(uint16_t xp, uint16_t yp, uint16_t w, uint16_t h,
+            const unsigned char *&buf) {
+    set_addr_window_(xp, yp, xp + w - 1, yp + h - 1);
+
+    this->command(ILI9481_CMD_MEMORY_WRITE);
+    {
+      this->start_data_();
+      this->write_array(buf, static_cast<size_t>(h * w * 3));
+      this->end_data_();
+    }
+  }
+
+  void set_addr_window_(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2) {
+    command(ILI9481_CMD_COLUMN_ADDRESS_SET);
+    {
+      start_data_();
+      write_byte(x1 >> 8);
+      write_byte(x1 & 0xFF);
+      write_byte(x2 >> 8);
+      write_byte(x2 & 0xFF);
+      end_data_();
+    }
+    command(ILI9481_CMD_PAGE_ADDRESS_SET);
+    {
+      start_data_();
+      write_byte(y1 >> 8);
+      write_byte(y1 & 0xFF);
+      write_byte(y2 >> 8);
+      write_byte(y2 & 0xFF);
+      end_data_();
+    }
+  }
+  void command(uint8_t value) {
+    this->start_command_();
+    this->write_byte(value);
+    this->end_command_();
+  }
+
+  void start_command_() {
+    this->dc_pin_->digital_write(false);
+    this->enable();
+  }
+  void end_command_() { this->disable(); }
+
+  void start_data_() {
+    this->dc_pin_->digital_write(true);
+    this->enable();
+  }
+  void end_data_() { this->disable(); }
+
+  void reset_() {
+    if (this->reset_pin_ != nullptr) {
+      this->reset_pin_->digital_write(false);
+      delay(20);
+      this->reset_pin_->digital_write(true);
+      delay(20);
+    }
+  }
+};
+
+void update_lcd_block(ILI9481Direct *lcd, std::string &x) {
+#if 0
+  std::string localPayload = x;
+  const unsigned char *buf = reinterpret_cast<const unsigned char*>(localPayload.data());
 #else
-  const char *buf = x.data();
+  const unsigned char *buf = reinterpret_cast<const unsigned char *>(x.data());
 #endif
+
   uint16_t seq, xp, yp, w, h;
 #define readu16()                          \
   (static_cast<const uint16_t>(*(buf++)) | \
@@ -25,27 +279,8 @@
   ESP_LOGD("dbg",
            "seq=%hu%s xp=%hu, yp=%hu, w=%hu, h=%hu, full payload=%d bytes", seq,
            seqDia, xp, yp, w, h, x.size());
-#if 1
-  ///// v1
-  id(lcd).draw_pixels_at(320+w-1-xp, yp, w, h,
-                         reinterpret_cast<const uint8_t*>(buf),
-                         COLOR_ORDER_BGR,
-                         COLOR_BITNESS_888,
-                         /*big_endian=*/false,
-                         /*x_offset=*/0,
-                         /*y_offset=*/0,
-                         /*x_pad=*/0);
-#elif 0
-  ///// v2
-  for (uint16_t y = 0; y < h; y++) {
-    uint16_t row = yp + y;
-    for (uint16_t x = 0; x < w; x++) {
-      id(lcd).draw_pixel_at(320-1-(xp + w-1 - x), row, Color(*buf++, *buf++, *buf++));
-    }
-    // App.feed_wdt();
-  }
-  #else
 
-#endif
-  id(lcd).update();
-}
\ No newline at end of file
+  lcd->blit(xp, yp, w, h, buf);
+}
+}  // namespace ili9xxx
+}  // namespace esphome