mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-30 22:53:59 +00:00 
			
		
		
		
	Speed up (and fix) ili9xxx display component. (#5406)
This commit is contained in:
		| @@ -2,6 +2,7 @@ import esphome.codegen as cg | ||||
| import esphome.config_validation as cv | ||||
| from esphome import core, pins | ||||
| from esphome.components import display, spi, font | ||||
| from esphome.components.display import validate_rotation | ||||
| from esphome.core import CORE, HexInt | ||||
| from esphome.const import ( | ||||
|     CONF_COLOR_PALETTE, | ||||
| @@ -13,6 +14,9 @@ from esphome.const import ( | ||||
|     CONF_PAGES, | ||||
|     CONF_RESET_PIN, | ||||
|     CONF_DIMENSIONS, | ||||
|     CONF_WIDTH, | ||||
|     CONF_HEIGHT, | ||||
|     CONF_ROTATION, | ||||
| ) | ||||
|  | ||||
| DEPENDENCIES = ["spi"] | ||||
| @@ -26,28 +30,35 @@ def AUTO_LOAD(): | ||||
|  | ||||
| CODEOWNERS = ["@nielsnl68", "@clydebarrow"] | ||||
|  | ||||
| ili9XXX_ns = cg.esphome_ns.namespace("ili9xxx") | ||||
| ili9XXXSPI = ili9XXX_ns.class_( | ||||
| ili9xxx_ns = cg.esphome_ns.namespace("ili9xxx") | ||||
| ILI9XXXDisplay = ili9xxx_ns.class_( | ||||
|     "ILI9XXXDisplay", cg.PollingComponent, spi.SPIDevice, display.DisplayBuffer | ||||
| ) | ||||
|  | ||||
| ILI9XXXColorMode = ili9XXX_ns.enum("ILI9XXXColorMode") | ||||
| ILI9XXXColorMode = ili9xxx_ns.enum("ILI9XXXColorMode") | ||||
| ColorOrder = display.display_ns.enum("ColorMode") | ||||
|  | ||||
| MODELS = { | ||||
|     "M5STACK": ili9XXX_ns.class_("ILI9XXXM5Stack", ili9XXXSPI), | ||||
|     "M5CORE": ili9XXX_ns.class_("ILI9XXXM5CORE", ili9XXXSPI), | ||||
|     "TFT_2.4": ili9XXX_ns.class_("ILI9XXXILI9341", ili9XXXSPI), | ||||
|     "TFT_2.4R": ili9XXX_ns.class_("ILI9XXXILI9342", ili9XXXSPI), | ||||
|     "ILI9341": ili9XXX_ns.class_("ILI9XXXILI9341", ili9XXXSPI), | ||||
|     "ILI9342": ili9XXX_ns.class_("ILI9XXXILI9342", ili9XXXSPI), | ||||
|     "ILI9481": ili9XXX_ns.class_("ILI9XXXILI9481", ili9XXXSPI), | ||||
|     "ILI9481-18": ili9XXX_ns.class_("ILI9XXXILI948118", ili9XXXSPI), | ||||
|     "ILI9486": ili9XXX_ns.class_("ILI9XXXILI9486", ili9XXXSPI), | ||||
|     "ILI9488": ili9XXX_ns.class_("ILI9XXXILI9488", ili9XXXSPI), | ||||
|     "ILI9488_A": ili9XXX_ns.class_("ILI9XXXILI9488A", ili9XXXSPI), | ||||
|     "ST7796": ili9XXX_ns.class_("ILI9XXXST7796", ili9XXXSPI), | ||||
|     "S3BOX": ili9XXX_ns.class_("ILI9XXXS3Box", ili9XXXSPI), | ||||
|     "S3BOX_LITE": ili9XXX_ns.class_("ILI9XXXS3BoxLite", ili9XXXSPI), | ||||
|     "M5STACK": ili9xxx_ns.class_("ILI9XXXM5Stack", ILI9XXXDisplay), | ||||
|     "M5CORE": ili9xxx_ns.class_("ILI9XXXM5CORE", ILI9XXXDisplay), | ||||
|     "TFT_2.4": ili9xxx_ns.class_("ILI9XXXILI9341", ILI9XXXDisplay), | ||||
|     "TFT_2.4R": ili9xxx_ns.class_("ILI9XXXILI9342", ILI9XXXDisplay), | ||||
|     "ILI9341": ili9xxx_ns.class_("ILI9XXXILI9341", ILI9XXXDisplay), | ||||
|     "ILI9342": ili9xxx_ns.class_("ILI9XXXILI9342", ILI9XXXDisplay), | ||||
|     "ILI9481": ili9xxx_ns.class_("ILI9XXXILI9481", ILI9XXXDisplay), | ||||
|     "ILI9481-18": ili9xxx_ns.class_("ILI9XXXILI948118", ILI9XXXDisplay), | ||||
|     "ILI9486": ili9xxx_ns.class_("ILI9XXXILI9486", ILI9XXXDisplay), | ||||
|     "ILI9488": ili9xxx_ns.class_("ILI9XXXILI9488", ILI9XXXDisplay), | ||||
|     "ILI9488_A": ili9xxx_ns.class_("ILI9XXXILI9488A", ILI9XXXDisplay), | ||||
|     "ST7796": ili9xxx_ns.class_("ILI9XXXST7796", ILI9XXXDisplay), | ||||
|     "ST7789V": ili9xxx_ns.class_("ILI9XXXST7789V", ILI9XXXDisplay), | ||||
|     "S3BOX": ili9xxx_ns.class_("ILI9XXXS3Box", ILI9XXXDisplay), | ||||
|     "S3BOX_LITE": ili9xxx_ns.class_("ILI9XXXS3BoxLite", ILI9XXXDisplay), | ||||
| } | ||||
|  | ||||
| COLOR_ORDERS = { | ||||
|     "RGB": ColorOrder.COLOR_ORDER_RGB, | ||||
|     "BGR": ColorOrder.COLOR_ORDER_BGR, | ||||
| } | ||||
|  | ||||
| COLOR_PALETTE = cv.one_of("NONE", "GRAYSCALE", "IMAGE_ADAPTIVE") | ||||
| @@ -55,6 +66,14 @@ COLOR_PALETTE = cv.one_of("NONE", "GRAYSCALE", "IMAGE_ADAPTIVE") | ||||
| CONF_LED_PIN = "led_pin" | ||||
| CONF_COLOR_PALETTE_IMAGES = "color_palette_images" | ||||
| CONF_INVERT_DISPLAY = "invert_display" | ||||
| CONF_INVERT_COLORS = "invert_colors" | ||||
| CONF_MIRROR_X = "mirror_x" | ||||
| CONF_MIRROR_Y = "mirror_y" | ||||
| CONF_SWAP_XY = "swap_xy" | ||||
| CONF_COLOR_ORDER = "color_order" | ||||
| CONF_OFFSET_HEIGHT = "offset_height" | ||||
| CONF_OFFSET_WIDTH = "offset_width" | ||||
| CONF_TRANSFORM = "transform" | ||||
|  | ||||
|  | ||||
| def _validate(config): | ||||
| @@ -77,6 +96,7 @@ def _validate(config): | ||||
|         "TFT_2.4R", | ||||
|         "ILI9341", | ||||
|         "ILI9342", | ||||
|         "ST7789V", | ||||
|     ]: | ||||
|         raise cv.Invalid( | ||||
|             "Provided model can't run on ESP8266. Use an ESP32 with PSRAM onboard" | ||||
| @@ -88,9 +108,19 @@ CONFIG_SCHEMA = cv.All( | ||||
|     font.validate_pillow_installed, | ||||
|     display.FULL_DISPLAY_SCHEMA.extend( | ||||
|         { | ||||
|             cv.GenerateID(): cv.declare_id(ili9XXXSPI), | ||||
|             cv.GenerateID(): cv.declare_id(ILI9XXXDisplay), | ||||
|             cv.Required(CONF_MODEL): cv.enum(MODELS, upper=True, space="_"), | ||||
|             cv.Optional(CONF_DIMENSIONS): cv.dimensions, | ||||
|             cv.Optional(CONF_DIMENSIONS): cv.Any( | ||||
|                 cv.dimensions, | ||||
|                 cv.Schema( | ||||
|                     { | ||||
|                         cv.Required(CONF_WIDTH): cv.int_, | ||||
|                         cv.Required(CONF_HEIGHT): cv.int_, | ||||
|                         cv.Optional(CONF_OFFSET_HEIGHT, default=0): cv.int_, | ||||
|                         cv.Optional(CONF_OFFSET_WIDTH, default=0): cv.int_, | ||||
|                     } | ||||
|                 ), | ||||
|             ), | ||||
|             cv.Required(CONF_DC_PIN): pins.gpio_output_pin_schema, | ||||
|             cv.Optional(CONF_RESET_PIN): pins.gpio_output_pin_schema, | ||||
|             cv.Optional(CONF_LED_PIN): cv.invalid( | ||||
| @@ -101,7 +131,19 @@ CONFIG_SCHEMA = cv.All( | ||||
|             cv.Optional(CONF_COLOR_PALETTE_IMAGES, default=[]): cv.ensure_list( | ||||
|                 cv.file_ | ||||
|             ), | ||||
|             cv.Optional(CONF_INVERT_DISPLAY): cv.boolean, | ||||
|             cv.Optional(CONF_INVERT_DISPLAY): cv.invalid( | ||||
|                 "'invert_display' has been replaced by 'invert_colors'" | ||||
|             ), | ||||
|             cv.Optional(CONF_INVERT_COLORS): cv.boolean, | ||||
|             cv.Optional(CONF_COLOR_ORDER): cv.one_of(*COLOR_ORDERS.keys(), upper=True), | ||||
|             cv.Exclusive(CONF_ROTATION, CONF_ROTATION): validate_rotation, | ||||
|             cv.Exclusive(CONF_TRANSFORM, CONF_ROTATION): cv.Schema( | ||||
|                 { | ||||
|                     cv.Optional(CONF_SWAP_XY, default=False): cv.boolean, | ||||
|                     cv.Optional(CONF_MIRROR_X, default=False): cv.boolean, | ||||
|                     cv.Optional(CONF_MIRROR_Y, default=False): cv.boolean, | ||||
|                 } | ||||
|             ), | ||||
|         } | ||||
|     ) | ||||
|     .extend(cv.polling_component_schema("1s")) | ||||
| @@ -119,6 +161,13 @@ async def to_code(config): | ||||
|     await spi.register_spi_device(var, config) | ||||
|     dc = await cg.gpio_pin_expression(config[CONF_DC_PIN]) | ||||
|     cg.add(var.set_dc_pin(dc)) | ||||
|     if CONF_COLOR_ORDER in config: | ||||
|         cg.add(var.set_color_order(COLOR_ORDERS[config[CONF_COLOR_ORDER]])) | ||||
|     if CONF_TRANSFORM in config: | ||||
|         transform = config[CONF_TRANSFORM] | ||||
|         cg.add(var.set_swap_xy(transform[CONF_SWAP_XY])) | ||||
|         cg.add(var.set_mirror_x(transform[CONF_MIRROR_X])) | ||||
|         cg.add(var.set_mirror_y(transform[CONF_MIRROR_Y])) | ||||
|  | ||||
|     if CONF_LAMBDA in config: | ||||
|         lambda_ = await cg.process_lambda( | ||||
| @@ -131,9 +180,17 @@ async def to_code(config): | ||||
|         cg.add(var.set_reset_pin(reset)) | ||||
|  | ||||
|     if CONF_DIMENSIONS in config: | ||||
|         cg.add( | ||||
|             var.set_dimentions(config[CONF_DIMENSIONS][0], config[CONF_DIMENSIONS][1]) | ||||
|         ) | ||||
|         dimensions = config[CONF_DIMENSIONS] | ||||
|         if isinstance(dimensions, dict): | ||||
|             cg.add(var.set_dimensions(dimensions[CONF_WIDTH], dimensions[CONF_HEIGHT])) | ||||
|             cg.add( | ||||
|                 var.set_offsets( | ||||
|                     dimensions[CONF_OFFSET_WIDTH], dimensions[CONF_OFFSET_HEIGHT] | ||||
|                 ) | ||||
|             ) | ||||
|         else: | ||||
|             (width, height) = dimensions | ||||
|             cg.add(var.set_dimensions(width, height)) | ||||
|  | ||||
|     rhs = None | ||||
|     if config[CONF_COLOR_PALETTE] == "GRAYSCALE": | ||||
| @@ -178,5 +235,5 @@ async def to_code(config): | ||||
|         prog_arr = cg.progmem_array(config[CONF_RAW_DATA_ID], rhs) | ||||
|         cg.add(var.set_palette(prog_arr)) | ||||
|  | ||||
|     if CONF_INVERT_DISPLAY in config: | ||||
|         cg.add(var.invert_display(config[CONF_INVERT_DISPLAY])) | ||||
|     if CONF_INVERT_COLORS in config: | ||||
|         cg.add(var.invert_colors(config[CONF_INVERT_COLORS])) | ||||
|   | ||||
| @@ -8,11 +8,31 @@ namespace esphome { | ||||
| namespace ili9xxx { | ||||
|  | ||||
| static const char *const TAG = "ili9xxx"; | ||||
| static const uint16_t SPI_SETUP_US = 100;         // estimated fixed overhead in microseconds for an SPI write | ||||
| static const uint16_t SPI_MAX_BLOCK_SIZE = 4092;  // Max size of continuous SPI transfer | ||||
|  | ||||
| // store a 16 bit value in a buffer, big endian. | ||||
| static inline void put16_be(uint8_t *buf, uint16_t value) { | ||||
|   buf[0] = value >> 8; | ||||
|   buf[1] = value; | ||||
| } | ||||
|  | ||||
| void ILI9XXXDisplay::setup() { | ||||
|   ESP_LOGD(TAG, "Setting up ILI9xxx"); | ||||
|  | ||||
|   this->setup_pins_(); | ||||
|   this->initialize(); | ||||
|   this->command(this->pre_invertdisplay_ ? ILI9XXX_INVON : ILI9XXX_INVOFF); | ||||
|   this->init_lcd_(); | ||||
|  | ||||
|   this->command(this->pre_invertcolors_ ? ILI9XXX_INVON : ILI9XXX_INVOFF); | ||||
|   // custom x/y transform and color order | ||||
|   uint8_t mad = this->color_order_ == display::COLOR_ORDER_BGR ? MADCTL_BGR : MADCTL_RGB; | ||||
|   if (this->swap_xy_) | ||||
|     mad |= MADCTL_MV; | ||||
|   if (this->mirror_x_) | ||||
|     mad |= MADCTL_MX; | ||||
|   if (this->mirror_y_) | ||||
|     mad |= MADCTL_MY; | ||||
|   this->send_command(ILI9XXX_MADCTL, &mad, 1); | ||||
|  | ||||
|   this->x_low_ = this->width_; | ||||
|   this->y_low_ = this->height_; | ||||
| @@ -47,6 +67,8 @@ void ILI9XXXDisplay::setup_pins_() { | ||||
|  | ||||
| void ILI9XXXDisplay::dump_config() { | ||||
|   LOG_DISPLAY("", "ili9xxx", this); | ||||
|   ESP_LOGCONFIG(TAG, "  Width Offset: %u", this->offset_x_); | ||||
|   ESP_LOGCONFIG(TAG, "  Height Offset: %u", this->offset_y_); | ||||
|   switch (this->buffer_color_mode_) { | ||||
|     case BITS_8_INDEXED: | ||||
|       ESP_LOGCONFIG(TAG, "  Color mode: 8bit Indexed"); | ||||
| @@ -64,8 +86,12 @@ void ILI9XXXDisplay::dump_config() { | ||||
|   ESP_LOGCONFIG(TAG, "  Data rate: %dMHz", (unsigned) (this->data_rate_ / 1000000)); | ||||
|  | ||||
|   LOG_PIN("  Reset Pin: ", this->reset_pin_); | ||||
|   LOG_PIN("  CS Pin: ", this->cs_); | ||||
|   LOG_PIN("  DC Pin: ", this->dc_pin_); | ||||
|   LOG_PIN("  Busy Pin: ", this->busy_pin_); | ||||
|   ESP_LOGCONFIG(TAG, "  Swap_xy: %s", YESNO(this->swap_xy_)); | ||||
|   ESP_LOGCONFIG(TAG, "  Mirror_x: %s", YESNO(this->mirror_x_)); | ||||
|   ESP_LOGCONFIG(TAG, "  Mirror_y: %s", YESNO(this->mirror_y_)); | ||||
|  | ||||
|   if (this->is_failed()) { | ||||
|     ESP_LOGCONFIG(TAG, "  => Failed to init Memory: YES!"); | ||||
| @@ -141,12 +167,14 @@ void HOT ILI9XXXDisplay::draw_absolute_pixel_internal(int x, int y, Color color) | ||||
|   } | ||||
|   if (updated) { | ||||
|     // low and high watermark may speed up drawing from buffer | ||||
|     this->x_low_ = (x < this->x_low_) ? x : this->x_low_; | ||||
|     this->y_low_ = (y < this->y_low_) ? y : this->y_low_; | ||||
|     this->x_high_ = (x > this->x_high_) ? x : this->x_high_; | ||||
|     this->y_high_ = (y > this->y_high_) ? y : this->y_high_; | ||||
|     // ESP_LOGVV(TAG, "=>>> pixel (x:%d, y:%d) (xl:%d, xh:%d, yl:%d, yh:%d", x, y, this->x_low_, this->x_high_, | ||||
|     //           this->y_low_, this->y_high_); | ||||
|     if (x < this->x_low_) | ||||
|       this->x_low_ = x; | ||||
|     if (y < this->y_low_) | ||||
|       this->y_low_ = y; | ||||
|     if (x > this->x_high_) | ||||
|       this->x_high_ = x; | ||||
|     if (y > this->y_high_) | ||||
|       this->y_high_ = y; | ||||
|   } | ||||
| } | ||||
|  | ||||
| @@ -165,59 +193,82 @@ void ILI9XXXDisplay::update() { | ||||
| } | ||||
|  | ||||
| void ILI9XXXDisplay::display_() { | ||||
|   // we will only update the changed window to the display | ||||
|   uint16_t w = this->x_high_ - this->x_low_ + 1;  // NOLINT | ||||
|   uint16_t h = this->y_high_ - this->y_low_ + 1;  // NOLINT | ||||
|   uint32_t start_pos = ((this->y_low_ * this->width_) + x_low_); | ||||
|  | ||||
|   uint8_t transfer_buffer[ILI9XXX_TRANSFER_BUFFER_SIZE]; | ||||
|   // check if something was displayed | ||||
|   if ((this->x_high_ < this->x_low_) || (this->y_high_ < this->y_low_)) { | ||||
|     ESP_LOGV(TAG, "Nothing to display"); | ||||
|     return; | ||||
|   } | ||||
|  | ||||
|   set_addr_window_(this->x_low_, this->y_low_, w, h); | ||||
|   // we will only update the changed rows to the display | ||||
|   size_t const w = this->x_high_ - this->x_low_ + 1; | ||||
|   size_t const h = this->y_high_ - this->y_low_ + 1; | ||||
|  | ||||
|   size_t mhz = this->data_rate_ / 1000000; | ||||
|   // estimate time for a single write | ||||
|   size_t sw_time = this->width_ * h * 16 / mhz + this->width_ * h * 2 / SPI_MAX_BLOCK_SIZE * SPI_SETUP_US * 2; | ||||
|   // estimate time for multiple writes | ||||
|   size_t mw_time = (w * h * 16) / mhz + w * h * 2 / ILI9XXX_TRANSFER_BUFFER_SIZE * SPI_SETUP_US; | ||||
|   ESP_LOGV(TAG, | ||||
|            "Start display(xlow:%d, ylow:%d, xhigh:%d, yhigh:%d, width:%d, " | ||||
|            "heigth:%d, start_pos:%" PRId32 ")", | ||||
|            this->x_low_, this->y_low_, this->x_high_, this->y_high_, w, h, start_pos); | ||||
|  | ||||
|   this->start_data_(); | ||||
|   for (uint16_t row = 0; row < h; row++) { | ||||
|     uint32_t pos = start_pos + (row * width_); | ||||
|     uint32_t rem = w; | ||||
|  | ||||
|     while (rem > 0) { | ||||
|       uint32_t sz = std::min(rem, ILI9XXX_TRANSFER_BUFFER_SIZE); | ||||
|       // ESP_LOGVV(TAG, "Send to display(pos:%d, rem:%d, zs:%d)", pos, rem, sz); | ||||
|       buffer_to_transfer_(pos, sz); | ||||
|       if (this->is_18bitdisplay_) { | ||||
|         for (uint32_t i = 0; i < sz; ++i) { | ||||
|           uint16_t color_val = transfer_buffer_[i]; | ||||
|  | ||||
|           uint8_t red = color_val & 0x1F; | ||||
|           uint8_t green = (color_val & 0x7E0) >> 5; | ||||
|           uint8_t blue = (color_val & 0xF800) >> 11; | ||||
|  | ||||
|           uint8_t pass_buff[3]; | ||||
|  | ||||
|           pass_buff[2] = (uint8_t) ((red / 32.0) * 64) << 2; | ||||
|           pass_buff[1] = (uint8_t) green << 2; | ||||
|           pass_buff[0] = (uint8_t) ((blue / 32.0) * 64) << 2; | ||||
|  | ||||
|           this->write_array(pass_buff, sizeof(pass_buff)); | ||||
|         } | ||||
|       } else { | ||||
|         this->write_array16(transfer_buffer_, sz); | ||||
|            "height:%d, mode=%d, 18bit=%d, sw_time=%dus, mw_time=%dus)", | ||||
|            this->x_low_, this->y_low_, this->x_high_, this->y_high_, w, h, this->buffer_color_mode_, | ||||
|            this->is_18bitdisplay_, sw_time, mw_time); | ||||
|   auto now = millis(); | ||||
|   this->enable(); | ||||
|   if (this->buffer_color_mode_ == BITS_16 && !this->is_18bitdisplay_ && sw_time < mw_time) { | ||||
|     // 16 bit mode maps directly to display format | ||||
|     ESP_LOGV(TAG, "Doing single write of %d bytes", this->width_ * h * 2); | ||||
|     set_addr_window_(0, this->y_low_, this->width_ - 1, this->y_high_); | ||||
|     this->write_array(this->buffer_ + this->y_low_ * this->width_ * 2, h * this->width_ * 2); | ||||
|   } else { | ||||
|     ESP_LOGV(TAG, "Doing multiple write"); | ||||
|     size_t rem = h * w;  // remaining number of pixels to write | ||||
|     set_addr_window_(this->x_low_, this->y_low_, this->x_high_, this->y_high_); | ||||
|     size_t idx = 0;    // index into transfer_buffer | ||||
|     size_t pixel = 0;  // pixel number offset | ||||
|     size_t pos = this->y_low_ * this->width_ + this->x_low_; | ||||
|     while (rem-- != 0) { | ||||
|       uint16_t color_val; | ||||
|       switch (this->buffer_color_mode_) { | ||||
|         case BITS_8: | ||||
|           color_val = display::ColorUtil::color_to_565(display::ColorUtil::rgb332_to_color(this->buffer_[pos++])); | ||||
|           break; | ||||
|         case BITS_8_INDEXED: | ||||
|           color_val = display::ColorUtil::color_to_565( | ||||
|               display::ColorUtil::index8_to_color_palette888(this->buffer_[pos++], this->palette_)); | ||||
|           break; | ||||
|         default:  // case BITS_16: | ||||
|           color_val = (buffer_[pos * 2] << 8) + buffer_[pos * 2 + 1]; | ||||
|           pos++; | ||||
|           break; | ||||
|       } | ||||
|       if (this->is_18bitdisplay_) { | ||||
|         transfer_buffer[idx++] = (uint8_t) ((color_val & 0xF800) >> 8);  // Blue | ||||
|         transfer_buffer[idx++] = (uint8_t) ((color_val & 0x7E0) >> 3);   // Green | ||||
|         transfer_buffer[idx++] = (uint8_t) (color_val << 3);             // Red | ||||
|       } else { | ||||
|         put16_be(transfer_buffer + idx, color_val); | ||||
|         idx += 2; | ||||
|       } | ||||
|       if (idx == ILI9XXX_TRANSFER_BUFFER_SIZE) { | ||||
|         this->write_array(transfer_buffer, idx); | ||||
|         idx = 0; | ||||
|         App.feed_wdt(); | ||||
|       } | ||||
|       // end of line? Skip to the next. | ||||
|       if (++pixel == w) { | ||||
|         pixel = 0; | ||||
|         pos += this->width_ - w; | ||||
|       } | ||||
|       pos += sz; | ||||
|       rem -= sz; | ||||
|     } | ||||
|     App.feed_wdt(); | ||||
|     // flush any balance. | ||||
|     if (idx != 0) { | ||||
|       this->write_array(transfer_buffer, idx); | ||||
|     } | ||||
|   } | ||||
|   this->end_data_(); | ||||
|  | ||||
|   this->disable(); | ||||
|   ESP_LOGV(TAG, "Data write took %dms", (unsigned) (millis() - now)); | ||||
|   // invalidate watermarks | ||||
|   this->x_low_ = this->width_; | ||||
|   this->y_low_ = this->height_; | ||||
| @@ -225,26 +276,6 @@ void ILI9XXXDisplay::display_() { | ||||
|   this->y_high_ = 0; | ||||
| } | ||||
|  | ||||
| uint32_t ILI9XXXDisplay::buffer_to_transfer_(uint32_t pos, uint32_t sz) { | ||||
|   for (uint32_t i = 0; i < sz; ++i) { | ||||
|     switch (this->buffer_color_mode_) { | ||||
|       case BITS_8_INDEXED: | ||||
|         transfer_buffer_[i] = display::ColorUtil::color_to_565( | ||||
|             display::ColorUtil::index8_to_color_palette888(this->buffer_[pos + i], this->palette_)); | ||||
|         break; | ||||
|       case BITS_16: | ||||
|         transfer_buffer_[i] = ((uint16_t) this->buffer_[(pos + i) * 2] << 8) | this->buffer_[((pos + i) * 2) + 1]; | ||||
|         continue; | ||||
|         break; | ||||
|       default: | ||||
|         transfer_buffer_[i] = | ||||
|             display::ColorUtil::color_to_565(display::ColorUtil::rgb332_to_color(this->buffer_[pos + i])); | ||||
|         break; | ||||
|     } | ||||
|   } | ||||
|   return sz; | ||||
| } | ||||
|  | ||||
| // should return the total size: return this->get_width_internal() * this->get_height_internal() * 2 // 16bit color | ||||
| // values per bit is huge | ||||
| uint32_t ILI9XXXDisplay::get_buffer_length_() { return this->get_width_internal() * this->get_height_internal(); } | ||||
| @@ -303,11 +334,11 @@ void ILI9XXXDisplay::reset_() { | ||||
|   } | ||||
| } | ||||
|  | ||||
| void ILI9XXXDisplay::init_lcd_(const uint8_t *init_cmd) { | ||||
| void ILI9XXXDisplay::init_lcd_() { | ||||
|   uint8_t cmd, x, num_args; | ||||
|   const uint8_t *addr = init_cmd; | ||||
|   while ((cmd = progmem_read_byte(addr++)) > 0) { | ||||
|     x = progmem_read_byte(addr++); | ||||
|   const uint8_t *addr = this->init_sequence_; | ||||
|   while ((cmd = *addr++) > 0) { | ||||
|     x = *addr++; | ||||
|     num_args = x & 0x7F; | ||||
|     send_command(cmd, addr, num_args); | ||||
|     addr += num_args; | ||||
| @@ -316,27 +347,29 @@ void ILI9XXXDisplay::init_lcd_(const uint8_t *init_cmd) { | ||||
|   } | ||||
| } | ||||
|  | ||||
| void ILI9XXXDisplay::set_addr_window_(uint16_t x1, uint16_t y1, uint16_t w, uint16_t h) { | ||||
|   uint16_t x2 = (x1 + w - 1), y2 = (y1 + h - 1); | ||||
|   this->command(ILI9XXX_CASET);  // Column address set | ||||
|   this->start_data_(); | ||||
|   this->write_byte(x1 >> 8); | ||||
|   this->write_byte(x1); | ||||
|   this->write_byte(x2 >> 8); | ||||
|   this->write_byte(x2); | ||||
|   this->end_data_(); | ||||
|   this->command(ILI9XXX_PASET);  // Row address set | ||||
|   this->start_data_(); | ||||
|   this->write_byte(y1 >> 8); | ||||
|   this->write_byte(y1); | ||||
|   this->write_byte(y2 >> 8); | ||||
|   this->write_byte(y2); | ||||
|   this->end_data_(); | ||||
|   this->command(ILI9XXX_RAMWR);  // Write to RAM | ||||
| // Tell the display controller where we want to draw pixels. | ||||
| // when called, the SPI should have already been enabled, only the D/C pin will be toggled here. | ||||
| void ILI9XXXDisplay::set_addr_window_(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2) { | ||||
|   uint8_t buf[4]; | ||||
|   this->dc_pin_->digital_write(false); | ||||
|   this->write_byte(ILI9XXX_CASET);  // Column address set | ||||
|   put16_be(buf, x1 + this->offset_x_); | ||||
|   put16_be(buf + 2, x2 + this->offset_x_); | ||||
|   this->dc_pin_->digital_write(true); | ||||
|   this->write_array(buf, sizeof buf); | ||||
|   this->dc_pin_->digital_write(false); | ||||
|   this->write_byte(ILI9XXX_PASET);  // Row address set | ||||
|   put16_be(buf, y1 + this->offset_y_); | ||||
|   put16_be(buf + 2, y2 + this->offset_y_); | ||||
|   this->dc_pin_->digital_write(true); | ||||
|   this->write_array(buf, sizeof buf); | ||||
|   this->dc_pin_->digital_write(false); | ||||
|   this->write_byte(ILI9XXX_RAMWR);  // Write to RAM | ||||
|   this->dc_pin_->digital_write(true); | ||||
| } | ||||
|  | ||||
| void ILI9XXXDisplay::invert_display(bool invert) { | ||||
|   this->pre_invertdisplay_ = invert; | ||||
| void ILI9XXXDisplay::invert_colors(bool invert) { | ||||
|   this->pre_invertcolors_ = invert; | ||||
|   if (is_ready()) { | ||||
|     this->command(invert ? ILI9XXX_INVON : ILI9XXX_INVOFF); | ||||
|   } | ||||
| @@ -345,132 +378,5 @@ void ILI9XXXDisplay::invert_display(bool invert) { | ||||
| int ILI9XXXDisplay::get_width_internal() { return this->width_; } | ||||
| int ILI9XXXDisplay::get_height_internal() { return this->height_; } | ||||
|  | ||||
| //   M5Stack display | ||||
| void ILI9XXXM5Stack::initialize() { | ||||
|   this->init_lcd_(INITCMD_M5STACK); | ||||
|   if (this->width_ == 0) | ||||
|     this->width_ = 320; | ||||
|   if (this->height_ == 0) | ||||
|     this->height_ = 240; | ||||
|   this->pre_invertdisplay_ = true; | ||||
| } | ||||
|  | ||||
| //   M5CORE display // Based on the configuration settings of M5stact's M5GFX code. | ||||
| void ILI9XXXM5CORE::initialize() { | ||||
|   this->init_lcd_(INITCMD_M5CORE); | ||||
|   if (this->width_ == 0) | ||||
|     this->width_ = 320; | ||||
|   if (this->height_ == 0) | ||||
|     this->height_ = 240; | ||||
|   this->pre_invertdisplay_ = true; | ||||
| } | ||||
|  | ||||
| //   24_TFT display | ||||
| void ILI9XXXILI9341::initialize() { | ||||
|   this->init_lcd_(INITCMD_ILI9341); | ||||
|   if (this->width_ == 0) | ||||
|     this->width_ = 240; | ||||
|   if (this->height_ == 0) | ||||
|     this->height_ = 320; | ||||
| } | ||||
| //   24_TFT rotated display | ||||
| void ILI9XXXILI9342::initialize() { | ||||
|   this->init_lcd_(INITCMD_ILI9341); | ||||
|   if (this->width_ == 0) { | ||||
|     this->width_ = 320; | ||||
|   } | ||||
|   if (this->height_ == 0) { | ||||
|     this->height_ = 240; | ||||
|   } | ||||
| } | ||||
|  | ||||
| //   35_TFT display | ||||
| void ILI9XXXILI9481::initialize() { | ||||
|   this->init_lcd_(INITCMD_ILI9481); | ||||
|   if (this->width_ == 0) { | ||||
|     this->width_ = 480; | ||||
|   } | ||||
|   if (this->height_ == 0) { | ||||
|     this->height_ = 320; | ||||
|   } | ||||
| } | ||||
|  | ||||
| void ILI9XXXILI948118::initialize() { | ||||
|   this->init_lcd_(INITCMD_ILI9481_18); | ||||
|   if (this->width_ == 0) { | ||||
|     this->width_ = 320; | ||||
|   } | ||||
|   if (this->height_ == 0) { | ||||
|     this->height_ = 480; | ||||
|   } | ||||
|   this->is_18bitdisplay_ = true; | ||||
| } | ||||
|  | ||||
| //   35_TFT display | ||||
| void ILI9XXXILI9486::initialize() { | ||||
|   this->init_lcd_(INITCMD_ILI9486); | ||||
|   if (this->width_ == 0) { | ||||
|     this->width_ = 480; | ||||
|   } | ||||
|   if (this->height_ == 0) { | ||||
|     this->height_ = 320; | ||||
|   } | ||||
| } | ||||
| //    40_TFT display | ||||
| void ILI9XXXILI9488::initialize() { | ||||
|   this->init_lcd_(INITCMD_ILI9488); | ||||
|   if (this->width_ == 0) { | ||||
|     this->width_ = 480; | ||||
|   } | ||||
|   if (this->height_ == 0) { | ||||
|     this->height_ = 320; | ||||
|   } | ||||
|   this->is_18bitdisplay_ = true; | ||||
| } | ||||
| //    40_TFT display | ||||
| void ILI9XXXILI9488A::initialize() { | ||||
|   this->init_lcd_(INITCMD_ILI9488_A); | ||||
|   if (this->width_ == 0) { | ||||
|     this->width_ = 480; | ||||
|   } | ||||
|   if (this->height_ == 0) { | ||||
|     this->height_ = 320; | ||||
|   } | ||||
|   this->is_18bitdisplay_ = true; | ||||
| } | ||||
| //    40_TFT display | ||||
| void ILI9XXXST7796::initialize() { | ||||
|   this->init_lcd_(INITCMD_ST7796); | ||||
|   if (this->width_ == 0) { | ||||
|     this->width_ = 320; | ||||
|   } | ||||
|   if (this->height_ == 0) { | ||||
|     this->height_ = 480; | ||||
|   } | ||||
| } | ||||
|  | ||||
| //   24_TFT rotated display | ||||
| void ILI9XXXS3Box::initialize() { | ||||
|   this->init_lcd_(INITCMD_S3BOX); | ||||
|   if (this->width_ == 0) { | ||||
|     this->width_ = 320; | ||||
|   } | ||||
|   if (this->height_ == 0) { | ||||
|     this->height_ = 240; | ||||
|   } | ||||
| } | ||||
|  | ||||
| //   24_TFT rotated display | ||||
| void ILI9XXXS3BoxLite::initialize() { | ||||
|   this->init_lcd_(INITCMD_S3BOXLITE); | ||||
|   if (this->width_ == 0) { | ||||
|     this->width_ = 320; | ||||
|   } | ||||
|   if (this->height_ == 0) { | ||||
|     this->height_ = 240; | ||||
|   } | ||||
|   this->pre_invertdisplay_ = true; | ||||
| } | ||||
|  | ||||
| }  // namespace ili9xxx | ||||
| }  // namespace esphome | ||||
|   | ||||
| @@ -7,7 +7,7 @@ | ||||
| namespace esphome { | ||||
| namespace ili9xxx { | ||||
|  | ||||
| const uint32_t ILI9XXX_TRANSFER_BUFFER_SIZE = 64; | ||||
| const size_t ILI9XXX_TRANSFER_BUFFER_SIZE = 126;  // ensure this is divisible by 6 | ||||
|  | ||||
| enum ILI9XXXColorMode { | ||||
|   BITS_8 = 0x08, | ||||
| @@ -23,20 +23,47 @@ class ILI9XXXDisplay : public display::DisplayBuffer, | ||||
|                        public spi::SPIDevice<spi::BIT_ORDER_MSB_FIRST, spi::CLOCK_POLARITY_LOW, | ||||
|                                              spi::CLOCK_PHASE_LEADING, ILI9XXXDisplay_DATA_RATE> { | ||||
|  public: | ||||
|   ILI9XXXDisplay() = default; | ||||
|   ILI9XXXDisplay(uint8_t const *init_sequence, int16_t width, int16_t height, bool invert_colors) | ||||
|       : init_sequence_{init_sequence}, width_{width}, height_{height}, pre_invertcolors_{invert_colors} { | ||||
|     uint8_t cmd, num_args, bits; | ||||
|     const uint8_t *addr = init_sequence; | ||||
|     while ((cmd = *addr++) != 0) { | ||||
|       num_args = *addr++ & 0x7F; | ||||
|       if (cmd == ILI9XXX_MADCTL) { | ||||
|         bits = *addr; | ||||
|         this->swap_xy_ = (bits & MADCTL_MV) != 0; | ||||
|         this->mirror_x_ = (bits & MADCTL_MX) != 0; | ||||
|         this->mirror_y_ = (bits & MADCTL_MY) != 0; | ||||
|         this->color_order_ = (bits & MADCTL_BGR) ? display::COLOR_ORDER_BGR : display::COLOR_ORDER_RGB; | ||||
|         break; | ||||
|       } | ||||
|       addr += num_args; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   void set_dc_pin(GPIOPin *dc_pin) { dc_pin_ = dc_pin; } | ||||
|   float get_setup_priority() const override; | ||||
|   void set_reset_pin(GPIOPin *reset) { this->reset_pin_ = reset; } | ||||
|   void set_palette(const uint8_t *palette) { this->palette_ = palette; } | ||||
|   void set_buffer_color_mode(ILI9XXXColorMode color_mode) { this->buffer_color_mode_ = color_mode; } | ||||
|   void set_dimentions(int16_t width, int16_t height) { | ||||
|   void set_dimensions(int16_t width, int16_t height) { | ||||
|     this->height_ = height; | ||||
|     this->width_ = width; | ||||
|   } | ||||
|   void invert_display(bool invert); | ||||
|   void set_offsets(int16_t offset_x, int16_t offset_y) { | ||||
|     this->offset_x_ = offset_x; | ||||
|     this->offset_y_ = offset_y; | ||||
|   } | ||||
|   void invert_colors(bool invert); | ||||
|   void command(uint8_t value); | ||||
|   void data(uint8_t value); | ||||
|   void send_command(uint8_t command_byte, const uint8_t *data_bytes, uint8_t num_data_bytes); | ||||
|   uint8_t read_command(uint8_t command_byte, uint8_t index); | ||||
|   void set_color_order(display::ColorOrder color_order) { this->color_order_ = color_order; } | ||||
|   void set_swap_xy(bool swap_xy) { this->swap_xy_ = swap_xy; } | ||||
|   void set_mirror_x(bool mirror_x) { this->mirror_x_ = mirror_x; } | ||||
|   void set_mirror_y(bool mirror_y) { this->mirror_y_ = mirror_y; } | ||||
|  | ||||
|   void update() override; | ||||
|  | ||||
| @@ -50,16 +77,17 @@ class ILI9XXXDisplay : public display::DisplayBuffer, | ||||
|  protected: | ||||
|   void draw_absolute_pixel_internal(int x, int y, Color color) override; | ||||
|   void setup_pins_(); | ||||
|   virtual void initialize() = 0; | ||||
|  | ||||
|   void display_(); | ||||
|   void init_lcd_(const uint8_t *init_cmd); | ||||
|   void set_addr_window_(uint16_t x, uint16_t y, uint16_t w, uint16_t h); | ||||
|  | ||||
|   void init_lcd_(); | ||||
|   void set_addr_window_(uint16_t x, uint16_t y, uint16_t x2, uint16_t y2); | ||||
|   void reset_(); | ||||
|  | ||||
|   uint8_t const *init_sequence_{}; | ||||
|   int16_t width_{0};   ///< Display width as modified by current rotation | ||||
|   int16_t height_{0};  ///< Display height as modified by current rotation | ||||
|   int16_t offset_x_{0}; | ||||
|   int16_t offset_y_{0}; | ||||
|   uint16_t x_low_{0}; | ||||
|   uint16_t y_low_{0}; | ||||
|   uint16_t x_high_{0}; | ||||
| @@ -77,10 +105,6 @@ class ILI9XXXDisplay : public display::DisplayBuffer, | ||||
|   void start_data_(); | ||||
|   void end_data_(); | ||||
|  | ||||
|   uint16_t transfer_buffer_[ILI9XXX_TRANSFER_BUFFER_SIZE]; | ||||
|  | ||||
|   uint32_t buffer_to_transfer_(uint32_t pos, uint32_t sz); | ||||
|  | ||||
|   GPIOPin *reset_pin_{nullptr}; | ||||
|   GPIOPin *dc_pin_{nullptr}; | ||||
|   GPIOPin *busy_pin_{nullptr}; | ||||
| @@ -88,77 +112,87 @@ class ILI9XXXDisplay : public display::DisplayBuffer, | ||||
|   bool prossing_update_ = false; | ||||
|   bool need_update_ = false; | ||||
|   bool is_18bitdisplay_ = false; | ||||
|   bool pre_invertdisplay_ = false; | ||||
|   bool pre_invertcolors_ = false; | ||||
|   display::ColorOrder color_order_{}; | ||||
|   bool swap_xy_{}; | ||||
|   bool mirror_x_{}; | ||||
|   bool mirror_y_{}; | ||||
| }; | ||||
|  | ||||
| //-----------   M5Stack display -------------- | ||||
| class ILI9XXXM5Stack : public ILI9XXXDisplay { | ||||
|  protected: | ||||
|   void initialize() override; | ||||
|  public: | ||||
|   ILI9XXXM5Stack() : ILI9XXXDisplay(INITCMD_M5STACK, 320, 240, true) {} | ||||
| }; | ||||
|  | ||||
| //-----------   M5Stack display -------------- | ||||
| class ILI9XXXM5CORE : public ILI9XXXDisplay { | ||||
|  protected: | ||||
|   void initialize() override; | ||||
|  public: | ||||
|   ILI9XXXM5CORE() : ILI9XXXDisplay(INITCMD_M5CORE, 320, 240, true) {} | ||||
| }; | ||||
|  | ||||
| //-----------   ST7789V display -------------- | ||||
| class ILI9XXXST7789V : public ILI9XXXDisplay { | ||||
|  public: | ||||
|   ILI9XXXST7789V() : ILI9XXXDisplay(INITCMD_ST7789V, 240, 320, false) {} | ||||
| }; | ||||
|  | ||||
| //-----------   ILI9XXX_24_TFT display -------------- | ||||
| class ILI9XXXILI9341 : public ILI9XXXDisplay { | ||||
|  protected: | ||||
|   void initialize() override; | ||||
|  public: | ||||
|   ILI9XXXILI9341() : ILI9XXXDisplay(INITCMD_ILI9341, 240, 320, false) {} | ||||
| }; | ||||
|  | ||||
| //-----------   ILI9XXX_24_TFT rotated display -------------- | ||||
| class ILI9XXXILI9342 : public ILI9XXXDisplay { | ||||
|  protected: | ||||
|   void initialize() override; | ||||
|  public: | ||||
|   ILI9XXXILI9342() : ILI9XXXDisplay(INITCMD_ILI9341, 320, 240, false) {} | ||||
| }; | ||||
|  | ||||
| //-----------   ILI9XXX_??_TFT rotated display -------------- | ||||
| class ILI9XXXILI9481 : public ILI9XXXDisplay { | ||||
|  protected: | ||||
|   void initialize() override; | ||||
|  public: | ||||
|   ILI9XXXILI9481() : ILI9XXXDisplay(INITCMD_ILI9481, 480, 320, false) {} | ||||
| }; | ||||
|  | ||||
| //-----------   ILI9481 in 18 bit mode -------------- | ||||
| class ILI9XXXILI948118 : public ILI9XXXDisplay { | ||||
|  protected: | ||||
|   void initialize() override; | ||||
|  public: | ||||
|   ILI9XXXILI948118() : ILI9XXXDisplay(INITCMD_ILI9481_18, 320, 480, true) {} | ||||
| }; | ||||
|  | ||||
| //-----------   ILI9XXX_35_TFT rotated display -------------- | ||||
| class ILI9XXXILI9486 : public ILI9XXXDisplay { | ||||
|  protected: | ||||
|   void initialize() override; | ||||
|  public: | ||||
|   ILI9XXXILI9486() : ILI9XXXDisplay(INITCMD_ILI9486, 480, 320, false) {} | ||||
| }; | ||||
|  | ||||
| //-----------   ILI9XXX_35_TFT rotated display -------------- | ||||
| class ILI9XXXILI9488 : public ILI9XXXDisplay { | ||||
|  protected: | ||||
|   void initialize() override; | ||||
|  public: | ||||
|   ILI9XXXILI9488() : ILI9XXXDisplay(INITCMD_ILI9488, 480, 320, true) {} | ||||
| }; | ||||
|  | ||||
| //-----------   ILI9XXX_35_TFT origin colors rotated display -------------- | ||||
| class ILI9XXXILI9488A : public ILI9XXXDisplay { | ||||
|  protected: | ||||
|   void initialize() override; | ||||
|  public: | ||||
|   ILI9XXXILI9488A() : ILI9XXXDisplay(INITCMD_ILI9488_A, 480, 320, true) {} | ||||
| }; | ||||
|  | ||||
| //-----------   ILI9XXX_35_TFT rotated display -------------- | ||||
| class ILI9XXXST7796 : public ILI9XXXDisplay { | ||||
|  protected: | ||||
|   void initialize() override; | ||||
|  public: | ||||
|   ILI9XXXST7796() : ILI9XXXDisplay(INITCMD_ST7796, 320, 480, false) {} | ||||
| }; | ||||
|  | ||||
| class ILI9XXXS3Box : public ILI9XXXDisplay { | ||||
|  protected: | ||||
|   void initialize() override; | ||||
|  public: | ||||
|   ILI9XXXS3Box() : ILI9XXXDisplay(INITCMD_S3BOX, 320, 240, false) {} | ||||
| }; | ||||
|  | ||||
| class ILI9XXXS3BoxLite : public ILI9XXXDisplay { | ||||
|  protected: | ||||
|   void initialize() override; | ||||
|  public: | ||||
|   ILI9XXXS3BoxLite() : ILI9XXXDisplay(INITCMD_S3BOXLITE, 320, 240, true) {} | ||||
| }; | ||||
|  | ||||
| }  // namespace ili9xxx | ||||
|   | ||||
| @@ -289,6 +289,33 @@ static const uint8_t PROGMEM INITCMD_S3BOXLITE[] = { | ||||
|   0x00                                   // End of list | ||||
| }; | ||||
|  | ||||
| static const uint8_t PROGMEM INITCMD_ST7789V[] = { | ||||
|   ILI9XXX_SLPOUT  , 0x80,                // Exit Sleep | ||||
|   ILI9XXX_DISPON  , 0x80,                // Display on | ||||
|   ILI9XXX_MADCTL  , 1, 0x08,             // Memory Access Control, BGR | ||||
|   ILI9XXX_DFUNCTR, 2, 0x0A, 0x82, | ||||
|   ILI9XXX_PIXFMT  , 1, 0x55, | ||||
|   ILI9XXX_FRMCTR2, 5, 0x0C, 0x0C, 0x00, 0x33, 0x33, | ||||
|   ILI9XXX_ETMOD, 1, 0x35, 0xBB, 1, 0x28, | ||||
|   ILI9XXX_PWCTR1  , 1, 0x0C,             // Power control VRH[5:0] | ||||
|   ILI9XXX_PWCTR3  , 2, 0x01, 0xFF, | ||||
|   ILI9XXX_PWCTR4  , 1, 0x10, | ||||
|   ILI9XXX_PWCTR5  , 1, 0x20, | ||||
|   ILI9XXX_IFCTR  , 1, 0x0F, | ||||
|   ILI9XXX_PWSET, 2, 0xA4, 0xA1, | ||||
|   ILI9XXX_GMCTRP1 , 14, | ||||
|   0xd0, 0x00, 0x02, 0x07, 0x0a, | ||||
|   0x28, 0x32, 0x44, 0x42, 0x06, 0x0e, | ||||
|   0x12, 0x14, 0x17, | ||||
|   ILI9XXX_GMCTRN1 , 14, | ||||
|   0xd0, 0x00, 0x02, 0x07, 0x0a, | ||||
|   0x28, 0x31, 0x54, 0x47, | ||||
|   0x0e, 0x1c, 0x17, 0x1b, | ||||
|   0x1e, | ||||
|   ILI9XXX_DISPON  , 0x80,                // Display on | ||||
|   0x00                                   // End of list | ||||
| }; | ||||
|  | ||||
| // clang-format on | ||||
| }  // namespace ili9xxx | ||||
| }  // namespace esphome | ||||
|   | ||||
| @@ -1554,6 +1554,8 @@ sensor: | ||||
|       memory_address: 0x7d | ||||
|       name: Adres sensor | ||||
|  | ||||
| psram: | ||||
|  | ||||
| esp32_touch: | ||||
|   setup_mode: false | ||||
|   iir_filter: 10ms | ||||
| @@ -2992,6 +2994,12 @@ display: | ||||
|     lambda: |- | ||||
|       it.rectangle(0, 0, it.get_width(), it.get_height()); | ||||
|   - platform: ili9xxx | ||||
|     invert_colors: true | ||||
|     dimensions: 320x240 | ||||
|     transform: | ||||
|       swap_xy: true | ||||
|       mirror_x: true | ||||
|       mirror_y: false | ||||
|     model: TFT 2.4 | ||||
|     cs_pin: GPIO5 | ||||
|     dc_pin: GPIO4 | ||||
| @@ -3000,6 +3008,11 @@ display: | ||||
|     lambda: |- | ||||
|       it.rectangle(0, 0, it.get_width(), it.get_height()); | ||||
|   - platform: ili9xxx | ||||
|     dimensions: | ||||
|       width: 320 | ||||
|       height: 240 | ||||
|       offset_width: 20 | ||||
|       offset_height: 10 | ||||
|     model: TFT 2.4 | ||||
|     cs_pin: GPIO5 | ||||
|     dc_pin: GPIO4 | ||||
|   | ||||
		Reference in New Issue
	
	Block a user