mirror of
https://github.com/esphome/esphome.git
synced 2024-11-21 22:48:10 +01:00
Renaming and extending the ili9341 to the ili9xxx component (#4275)
* - Removed cleaning the screen twice. \Should be handled by `DisplayBuffer::init_internal_();` - Made ili9341::initalize() protected and renamed \ it to ili9341::initalize(). - ili9341::initalize() should only init the display \ and set the width and heigth. * removed to much * clang format fixes * removing trailing underscors for protected virtual methods * removed the "override" on display() * clang fixes * restored old changes * Renamed the ili9341 platform to ili9xxx and added multiple drivers as well. including PR #3848 * fixed most of the clang reported issues * fixed reported issues * last fixes * Setting the right codeowners * missing changes * fixed naming Display() method. * clang again * clang fix * fixes reported by @jesserockz & @gpambrozio * a change to display.py removing an unneeded var * re-introduce **backlight** option. * update the ili9488 initialization * update the ili9488 initialization and fix typo * fixed typo * add missing constants * swap height and width back for the ili9488 * init fixes ili9488 * fixed lint issue testing the init code * oeps * init fixes ili9488 * fixed wrong define * fixed wrong define again * removed some spaces * revert to ili9341 * Remove parts that where used for the switchplate * lint fixes and removing unused function * fix error and introducing 16bit color option * fix error and introducing 16bit color option * fix clang issue * clang fix * clang issue again * is this what clang exprect * clang fix * clang fix * try again * let try again * and again * and the last clang fix * remove the need of wifi * update dimentions * update ili8488 init code. * update dimentions * allow to change height and width * dump color mode config * fix * fix * modify logging * referd back unrelated change * code formatting commit and moving functions around * add missing ; * update code * update code * use the correct write_array for sending uint16_t * fix panic loop * fix panic loop * - update the test file - fixed sending display data * clang fixes * clang fixes * clang fixes again * remove .gitignore items * remove .gitignore items * make sure Update() can can not be called while called * clang correction * adding a test yaml for the ili9341 * Update ili9341 example * Make test ili9xxx/tests only local * restore back old ili9341 driver code * Add a new config for the M5Core * fix clang request * reverd to restore of the old ili9341 there is no proper way to say it is depricated. * Remove the backlight/led pin from the config. You need to use a proper light platform component * Ili9488init changes (#88) Fixed ILI9488 init settings, and adjusted pixel handling code to push pixels in 18 bit format. This does not change the internal 16-bit representation. * fixed some leftover clang issues from the merge. * fixed the slang-tidy request. * remove `backlight_pin` warning. --------- Co-authored-by: JD Steffen <jdsteffen81@gmail.com>
This commit is contained in:
parent
f3a969d35c
commit
336c2d34e6
12 changed files with 917 additions and 672 deletions
|
@ -111,6 +111,7 @@ esphome/components/hte501/* @Stock-M
|
|||
esphome/components/hydreon_rgxx/* @functionpointer
|
||||
esphome/components/i2c/* @esphome/core
|
||||
esphome/components/i2s_audio/* @jesserockz
|
||||
esphome/components/ili9xxx/* @nielsnl68
|
||||
esphome/components/improv_base/* @esphome/core
|
||||
esphome/components/improv_serial/* @esphome/core
|
||||
esphome/components/ina260/* @MrEditor97
|
||||
|
|
|
@ -1,153 +1,5 @@
|
|||
import esphome.codegen as cg
|
||||
import esphome.config_validation as cv
|
||||
from esphome import core, pins
|
||||
from esphome.components import display, spi
|
||||
from esphome.const import (
|
||||
CONF_COLOR_PALETTE,
|
||||
CONF_DC_PIN,
|
||||
CONF_ID,
|
||||
CONF_LAMBDA,
|
||||
CONF_MODEL,
|
||||
CONF_PAGES,
|
||||
CONF_RAW_DATA_ID,
|
||||
CONF_RESET_PIN,
|
||||
|
||||
CONFIG_SCHEMA = cv.invalid(
|
||||
"The ili9341 platform component has been renamed to ili9xxx."
|
||||
)
|
||||
from esphome.core import CORE, HexInt
|
||||
|
||||
DEPENDENCIES = ["spi"]
|
||||
|
||||
CONF_COLOR_PALETTE_IMAGES = "color_palette_images"
|
||||
CONF_LED_PIN = "led_pin"
|
||||
|
||||
ili9341_ns = cg.esphome_ns.namespace("ili9341")
|
||||
ili9341 = ili9341_ns.class_(
|
||||
"ILI9341Display", cg.PollingComponent, spi.SPIDevice, display.DisplayBuffer
|
||||
)
|
||||
ILI9341M5Stack = ili9341_ns.class_("ILI9341M5Stack", ili9341)
|
||||
ILI9341TFT24 = ili9341_ns.class_("ILI9341TFT24", ili9341)
|
||||
ILI9341TFT24R = ili9341_ns.class_("ILI9341TFT24R", ili9341)
|
||||
|
||||
ILI9341Model = ili9341_ns.enum("ILI9341Model")
|
||||
ILI9341ColorMode = ili9341_ns.enum("ILI9341ColorMode")
|
||||
|
||||
MODELS = {
|
||||
"M5STACK": ILI9341Model.M5STACK,
|
||||
"TFT_2.4": ILI9341Model.TFT_24,
|
||||
"TFT_2.4R": ILI9341Model.TFT_24R,
|
||||
}
|
||||
|
||||
ILI9341_MODEL = cv.enum(MODELS, upper=True, space="_")
|
||||
|
||||
COLOR_PALETTE = cv.one_of("NONE", "GRAYSCALE", "IMAGE_ADAPTIVE")
|
||||
|
||||
|
||||
def _validate(config):
|
||||
if config.get(CONF_COLOR_PALETTE) == "IMAGE_ADAPTIVE" and not config.get(
|
||||
CONF_COLOR_PALETTE_IMAGES
|
||||
):
|
||||
raise cv.Invalid(
|
||||
"Color palette in IMAGE_ADAPTIVE mode requires at least one 'color_palette_images' entry to generate palette"
|
||||
)
|
||||
if (
|
||||
config.get(CONF_COLOR_PALETTE_IMAGES)
|
||||
and config.get(CONF_COLOR_PALETTE) != "IMAGE_ADAPTIVE"
|
||||
):
|
||||
raise cv.Invalid(
|
||||
"Providing color palette images requires palette mode to be 'IMAGE_ADAPTIVE'"
|
||||
)
|
||||
return config
|
||||
|
||||
|
||||
CONFIG_SCHEMA = cv.All(
|
||||
display.FULL_DISPLAY_SCHEMA.extend(
|
||||
{
|
||||
cv.GenerateID(): cv.declare_id(ili9341),
|
||||
cv.Required(CONF_MODEL): ILI9341_MODEL,
|
||||
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): pins.gpio_output_pin_schema,
|
||||
cv.Optional(CONF_COLOR_PALETTE, default="NONE"): COLOR_PALETTE,
|
||||
cv.Optional(CONF_COLOR_PALETTE_IMAGES, default=[]): cv.ensure_list(
|
||||
cv.file_
|
||||
),
|
||||
cv.GenerateID(CONF_RAW_DATA_ID): cv.declare_id(cg.uint8),
|
||||
}
|
||||
)
|
||||
.extend(cv.polling_component_schema("1s"))
|
||||
.extend(spi.spi_device_schema(False)),
|
||||
cv.has_at_most_one_key(CONF_PAGES, CONF_LAMBDA),
|
||||
_validate,
|
||||
)
|
||||
|
||||
|
||||
async def to_code(config):
|
||||
if config[CONF_MODEL] == "M5STACK":
|
||||
lcd_type = ILI9341M5Stack
|
||||
if config[CONF_MODEL] == "TFT_2.4":
|
||||
lcd_type = ILI9341TFT24
|
||||
if config[CONF_MODEL] == "TFT_2.4R":
|
||||
lcd_type = ILI9341TFT24R
|
||||
rhs = lcd_type.new()
|
||||
var = cg.Pvariable(config[CONF_ID], rhs)
|
||||
|
||||
await cg.register_component(var, config)
|
||||
await display.register_display(var, config)
|
||||
await spi.register_spi_device(var, config)
|
||||
cg.add(var.set_model(config[CONF_MODEL]))
|
||||
dc = await cg.gpio_pin_expression(config[CONF_DC_PIN])
|
||||
cg.add(var.set_dc_pin(dc))
|
||||
|
||||
if CONF_LAMBDA in config:
|
||||
lambda_ = await cg.process_lambda(
|
||||
config[CONF_LAMBDA], [(display.DisplayBufferRef, "it")], return_type=cg.void
|
||||
)
|
||||
cg.add(var.set_writer(lambda_))
|
||||
if CONF_RESET_PIN in config:
|
||||
reset = await cg.gpio_pin_expression(config[CONF_RESET_PIN])
|
||||
cg.add(var.set_reset_pin(reset))
|
||||
if CONF_LED_PIN in config:
|
||||
led_pin = await cg.gpio_pin_expression(config[CONF_LED_PIN])
|
||||
cg.add(var.set_led_pin(led_pin))
|
||||
|
||||
rhs = None
|
||||
if config[CONF_COLOR_PALETTE] == "GRAYSCALE":
|
||||
cg.add(var.set_buffer_color_mode(ILI9341ColorMode.BITS_8_INDEXED))
|
||||
rhs = []
|
||||
for x in range(256):
|
||||
rhs.extend([HexInt(x), HexInt(x), HexInt(x)])
|
||||
elif config[CONF_COLOR_PALETTE] == "IMAGE_ADAPTIVE":
|
||||
cg.add(var.set_buffer_color_mode(ILI9341ColorMode.BITS_8_INDEXED))
|
||||
from PIL import Image
|
||||
|
||||
def load_image(filename):
|
||||
path = CORE.relative_config_path(filename)
|
||||
try:
|
||||
return Image.open(path)
|
||||
except Exception as e:
|
||||
raise core.EsphomeError(f"Could not load image file {path}: {e}")
|
||||
|
||||
# make a wide horizontal combined image.
|
||||
images = [load_image(x) for x in config[CONF_COLOR_PALETTE_IMAGES]]
|
||||
total_width = sum(i.width for i in images)
|
||||
max_height = max(i.height for i in images)
|
||||
|
||||
ref_image = Image.new("RGB", (total_width, max_height))
|
||||
x = 0
|
||||
for i in images:
|
||||
ref_image.paste(i, (x, 0))
|
||||
x = x + i.width
|
||||
|
||||
# reduce the colors on combined image to 256.
|
||||
converted = ref_image.convert("P", palette=Image.ADAPTIVE, colors=256)
|
||||
# if you want to verify how the images look use
|
||||
# ref_image.save("ref_in.png")
|
||||
# converted.save("ref_out.png")
|
||||
palette = converted.getpalette()
|
||||
assert len(palette) == 256 * 3
|
||||
rhs = palette
|
||||
else:
|
||||
cg.add(var.set_buffer_color_mode(ILI9341ColorMode.BITS_8))
|
||||
|
||||
if rhs is not None:
|
||||
prog_arr = cg.progmem_array(config[CONF_RAW_DATA_ID], rhs)
|
||||
cg.add(var.set_palette(prog_arr))
|
||||
|
|
|
@ -1,83 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
namespace esphome {
|
||||
namespace ili9341 {
|
||||
|
||||
// Color definitions
|
||||
// clang-format off
|
||||
static const uint8_t MADCTL_MY = 0x80; ///< Bit 7 Bottom to top
|
||||
static const uint8_t MADCTL_MX = 0x40; ///< Bit 6 Right to left
|
||||
static const uint8_t MADCTL_MV = 0x20; ///< Bit 5 Reverse Mode
|
||||
static const uint8_t MADCTL_ML = 0x10; ///< Bit 4 LCD refresh Bottom to top
|
||||
static const uint8_t MADCTL_RGB = 0x00; ///< Bit 3 Red-Green-Blue pixel order
|
||||
static const uint8_t MADCTL_BGR = 0x08; ///< Bit 3 Blue-Green-Red pixel order
|
||||
static const uint8_t MADCTL_MH = 0x04; ///< Bit 2 LCD refresh right to left
|
||||
// clang-format on
|
||||
|
||||
static const uint16_t ILI9341_TFTWIDTH = 320; ///< ILI9341 max TFT width
|
||||
static const uint16_t ILI9341_TFTHEIGHT = 240; ///< ILI9341 max TFT height
|
||||
|
||||
// All ILI9341 specific commands some are used by init()
|
||||
static const uint8_t ILI9341_NOP = 0x00;
|
||||
static const uint8_t ILI9341_SWRESET = 0x01;
|
||||
static const uint8_t ILI9341_RDDID = 0x04;
|
||||
static const uint8_t ILI9341_RDDST = 0x09;
|
||||
|
||||
static const uint8_t ILI9341_SLPIN = 0x10;
|
||||
static const uint8_t ILI9341_SLPOUT = 0x11;
|
||||
static const uint8_t ILI9341_PTLON = 0x12;
|
||||
static const uint8_t ILI9341_NORON = 0x13;
|
||||
|
||||
static const uint8_t ILI9341_RDMODE = 0x0A;
|
||||
static const uint8_t ILI9341_RDMADCTL = 0x0B;
|
||||
static const uint8_t ILI9341_RDPIXFMT = 0x0C;
|
||||
static const uint8_t ILI9341_RDIMGFMT = 0x0A;
|
||||
static const uint8_t ILI9341_RDSELFDIAG = 0x0F;
|
||||
|
||||
static const uint8_t ILI9341_INVOFF = 0x20;
|
||||
static const uint8_t ILI9341_INVON = 0x21;
|
||||
static const uint8_t ILI9341_GAMMASET = 0x26;
|
||||
static const uint8_t ILI9341_DISPOFF = 0x28;
|
||||
static const uint8_t ILI9341_DISPON = 0x29;
|
||||
|
||||
static const uint8_t ILI9341_CASET = 0x2A;
|
||||
static const uint8_t ILI9341_PASET = 0x2B;
|
||||
static const uint8_t ILI9341_RAMWR = 0x2C;
|
||||
static const uint8_t ILI9341_RAMRD = 0x2E;
|
||||
|
||||
static const uint8_t ILI9341_PTLAR = 0x30;
|
||||
static const uint8_t ILI9341_VSCRDEF = 0x33;
|
||||
static const uint8_t ILI9341_MADCTL = 0x36;
|
||||
static const uint8_t ILI9341_VSCRSADD = 0x37;
|
||||
static const uint8_t ILI9341_PIXFMT = 0x3A;
|
||||
|
||||
static const uint8_t ILI9341_WRDISBV = 0x51;
|
||||
static const uint8_t ILI9341_RDDISBV = 0x52;
|
||||
static const uint8_t ILI9341_WRCTRLD = 0x53;
|
||||
|
||||
static const uint8_t ILI9341_FRMCTR1 = 0xB1;
|
||||
static const uint8_t ILI9341_FRMCTR2 = 0xB2;
|
||||
static const uint8_t ILI9341_FRMCTR3 = 0xB3;
|
||||
static const uint8_t ILI9341_INVCTR = 0xB4;
|
||||
static const uint8_t ILI9341_DFUNCTR = 0xB6;
|
||||
|
||||
static const uint8_t ILI9341_PWCTR1 = 0xC0;
|
||||
static const uint8_t ILI9341_PWCTR2 = 0xC1;
|
||||
static const uint8_t ILI9341_PWCTR3 = 0xC2;
|
||||
static const uint8_t ILI9341_PWCTR4 = 0xC3;
|
||||
static const uint8_t ILI9341_PWCTR5 = 0xC4;
|
||||
static const uint8_t ILI9341_VMCTR1 = 0xC5;
|
||||
static const uint8_t ILI9341_VMCTR2 = 0xC7;
|
||||
|
||||
static const uint8_t ILI9341_RDID4 = 0xD3;
|
||||
static const uint8_t ILI9341_RDINDEX = 0xD9;
|
||||
static const uint8_t ILI9341_RDID1 = 0xDA;
|
||||
static const uint8_t ILI9341_RDID2 = 0xDB;
|
||||
static const uint8_t ILI9341_RDID3 = 0xDC;
|
||||
static const uint8_t ILI9341_RDIDX = 0xDD; // TBC
|
||||
|
||||
static const uint8_t ILI9341_GMCTRP1 = 0xE0;
|
||||
static const uint8_t ILI9341_GMCTRN1 = 0xE1;
|
||||
|
||||
} // namespace ili9341
|
||||
} // namespace esphome
|
|
@ -1,308 +0,0 @@
|
|||
#include "ili9341_display.h"
|
||||
#include "esphome/core/log.h"
|
||||
#include "esphome/core/application.h"
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/core/hal.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace ili9341 {
|
||||
|
||||
static const char *const TAG = "ili9341";
|
||||
|
||||
void ILI9341Display::setup_pins_() {
|
||||
this->dc_pin_->setup(); // OUTPUT
|
||||
this->dc_pin_->digital_write(false);
|
||||
if (this->reset_pin_ != nullptr) {
|
||||
this->reset_pin_->setup(); // OUTPUT
|
||||
this->reset_pin_->digital_write(true);
|
||||
}
|
||||
if (this->led_pin_ != nullptr) {
|
||||
this->led_pin_->setup();
|
||||
this->led_pin_->digital_write(true);
|
||||
}
|
||||
this->spi_setup();
|
||||
|
||||
this->reset_();
|
||||
}
|
||||
|
||||
void ILI9341Display::dump_config() {
|
||||
LOG_DISPLAY("", "ili9341", this);
|
||||
LOG_PIN(" Reset Pin: ", this->reset_pin_);
|
||||
LOG_PIN(" DC Pin: ", this->dc_pin_);
|
||||
LOG_PIN(" Busy Pin: ", this->busy_pin_);
|
||||
LOG_UPDATE_INTERVAL(this);
|
||||
}
|
||||
|
||||
float ILI9341Display::get_setup_priority() const { return setup_priority::HARDWARE; }
|
||||
|
||||
void ILI9341Display::command(uint8_t value) {
|
||||
this->start_command_();
|
||||
this->write_byte(value);
|
||||
this->end_command_();
|
||||
}
|
||||
|
||||
void ILI9341Display::reset_() {
|
||||
if (this->reset_pin_ != nullptr) {
|
||||
this->reset_pin_->digital_write(false);
|
||||
delay(10);
|
||||
this->reset_pin_->digital_write(true);
|
||||
delay(10);
|
||||
}
|
||||
}
|
||||
|
||||
void ILI9341Display::data(uint8_t value) {
|
||||
this->start_data_();
|
||||
this->write_byte(value);
|
||||
this->end_data_();
|
||||
}
|
||||
|
||||
void ILI9341Display::send_command(uint8_t command_byte, const uint8_t *data_bytes, uint8_t num_data_bytes) {
|
||||
this->command(command_byte); // Send the command byte
|
||||
this->start_data_();
|
||||
this->write_array(data_bytes, num_data_bytes);
|
||||
this->end_data_();
|
||||
}
|
||||
|
||||
uint8_t ILI9341Display::read_command(uint8_t command_byte, uint8_t index) {
|
||||
uint8_t data = 0x10 + index;
|
||||
this->send_command(0xD9, &data, 1); // Set Index Register
|
||||
uint8_t result;
|
||||
this->start_command_();
|
||||
this->write_byte(command_byte);
|
||||
this->start_data_();
|
||||
do {
|
||||
result = this->read_byte();
|
||||
} while (index--);
|
||||
this->end_data_();
|
||||
return result;
|
||||
}
|
||||
|
||||
void ILI9341Display::update() {
|
||||
this->do_update_();
|
||||
this->display_();
|
||||
}
|
||||
|
||||
void ILI9341Display::display_() {
|
||||
// we will only update the changed window to the display
|
||||
uint16_t w = this->x_high_ - this->x_low_ + 1;
|
||||
uint16_t h = this->y_high_ - this->y_low_ + 1;
|
||||
uint32_t start_pos = ((this->y_low_ * this->width_) + x_low_);
|
||||
|
||||
// check if something was displayed
|
||||
if ((this->x_high_ < this->x_low_) || (this->y_high_ < this->y_low_)) {
|
||||
return;
|
||||
}
|
||||
|
||||
set_addr_window_(this->x_low_, this->y_low_, w, h);
|
||||
|
||||
ESP_LOGVV("ILI9341", "Start ILI9341Display::display_(xl:%d, xh:%d, yl:%d, yh:%d, w:%d, h:%d, start_pos:%d)",
|
||||
this->x_low_, this->x_high_, this->y_low_, 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 = buffer_to_transfer_(pos, rem);
|
||||
this->write_array(transfer_buffer_, 2 * sz);
|
||||
pos += sz;
|
||||
rem -= sz;
|
||||
App.feed_wdt();
|
||||
}
|
||||
App.feed_wdt();
|
||||
}
|
||||
this->end_data_();
|
||||
|
||||
// invalidate watermarks
|
||||
this->x_low_ = this->width_;
|
||||
this->y_low_ = this->height_;
|
||||
this->x_high_ = 0;
|
||||
this->y_high_ = 0;
|
||||
}
|
||||
|
||||
void ILI9341Display::fill(Color color) {
|
||||
uint8_t color332 = 0;
|
||||
if (this->buffer_color_mode_ == BITS_8) {
|
||||
color332 = display::ColorUtil::color_to_332(color);
|
||||
} else { // if (this->buffer_color_mode_ == BITS_8_INDEXED)
|
||||
color332 = display::ColorUtil::color_to_index8_palette888(color, this->palette_);
|
||||
}
|
||||
memset(this->buffer_, color332, this->get_buffer_length_());
|
||||
this->x_low_ = 0;
|
||||
this->y_low_ = 0;
|
||||
this->x_high_ = this->get_width_internal() - 1;
|
||||
this->y_high_ = this->get_height_internal() - 1;
|
||||
}
|
||||
|
||||
void ILI9341Display::fill_internal_(uint8_t color) {
|
||||
memset(transfer_buffer_, color, sizeof(transfer_buffer_));
|
||||
|
||||
uint32_t rem = (this->get_buffer_length_() * 2);
|
||||
|
||||
this->set_addr_window_(0, 0, this->get_width_internal(), this->get_height_internal());
|
||||
this->start_data_();
|
||||
|
||||
while (rem > 0) {
|
||||
size_t sz = rem <= sizeof(transfer_buffer_) ? rem : sizeof(transfer_buffer_);
|
||||
this->write_array(transfer_buffer_, sz);
|
||||
rem -= sz;
|
||||
}
|
||||
|
||||
this->end_data_();
|
||||
|
||||
memset(buffer_, color, this->get_buffer_length_());
|
||||
}
|
||||
|
||||
void ILI9341Display::rotate_my_(uint8_t m) {
|
||||
uint8_t rotation = m & 3; // can't be higher than 3
|
||||
switch (rotation) {
|
||||
case 0:
|
||||
m = (MADCTL_MX | MADCTL_BGR);
|
||||
// _width = ILI9341_TFTWIDTH;
|
||||
// _height = ILI9341_TFTHEIGHT;
|
||||
break;
|
||||
case 1:
|
||||
m = (MADCTL_MV | MADCTL_BGR);
|
||||
// _width = ILI9341_TFTHEIGHT;
|
||||
// _height = ILI9341_TFTWIDTH;
|
||||
break;
|
||||
case 2:
|
||||
m = (MADCTL_MY | MADCTL_BGR);
|
||||
// _width = ILI9341_TFTWIDTH;
|
||||
// _height = ILI9341_TFTHEIGHT;
|
||||
break;
|
||||
case 3:
|
||||
m = (MADCTL_MX | MADCTL_MY | MADCTL_MV | MADCTL_BGR);
|
||||
// _width = ILI9341_TFTHEIGHT;
|
||||
// _height = ILI9341_TFTWIDTH;
|
||||
break;
|
||||
}
|
||||
|
||||
this->command(ILI9341_MADCTL);
|
||||
this->data(m);
|
||||
}
|
||||
|
||||
void HOT ILI9341Display::draw_absolute_pixel_internal(int x, int y, Color color) {
|
||||
if (x >= this->get_width_internal() || x < 0 || y >= this->get_height_internal() || y < 0)
|
||||
return;
|
||||
|
||||
uint32_t pos = (y * width_) + x;
|
||||
uint8_t new_color;
|
||||
|
||||
if (this->buffer_color_mode_ == BITS_8) {
|
||||
new_color = display::ColorUtil::color_to_332(color, display::ColorOrder::COLOR_ORDER_RGB);
|
||||
} else { // if (this->buffer_color_mode_ == BITS_8_INDEXED) {
|
||||
new_color = display::ColorUtil::color_to_index8_palette888(color, this->palette_);
|
||||
}
|
||||
|
||||
if (buffer_[pos] != new_color) {
|
||||
buffer_[pos] = new_color;
|
||||
// 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_;
|
||||
}
|
||||
}
|
||||
|
||||
// should return the total size: return this->get_width_internal() * this->get_height_internal() * 2 // 16bit color
|
||||
// values per bit is huge
|
||||
uint32_t ILI9341Display::get_buffer_length_() { return this->get_width_internal() * this->get_height_internal(); }
|
||||
|
||||
void ILI9341Display::start_command_() {
|
||||
this->dc_pin_->digital_write(false);
|
||||
this->enable();
|
||||
}
|
||||
|
||||
void ILI9341Display::end_command_() { this->disable(); }
|
||||
void ILI9341Display::start_data_() {
|
||||
this->dc_pin_->digital_write(true);
|
||||
this->enable();
|
||||
}
|
||||
void ILI9341Display::end_data_() { this->disable(); }
|
||||
|
||||
void ILI9341Display::init_lcd_(const uint8_t *init_cmd) {
|
||||
uint8_t cmd, x, num_args;
|
||||
const uint8_t *addr = init_cmd;
|
||||
while ((cmd = progmem_read_byte(addr++)) > 0) {
|
||||
x = progmem_read_byte(addr++);
|
||||
num_args = x & 0x7F;
|
||||
send_command(cmd, addr, num_args);
|
||||
addr += num_args;
|
||||
if (x & 0x80)
|
||||
delay(150); // NOLINT
|
||||
}
|
||||
}
|
||||
|
||||
void ILI9341Display::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(ILI9341_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(ILI9341_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(ILI9341_RAMWR); // Write to RAM
|
||||
}
|
||||
|
||||
void ILI9341Display::invert_display_(bool invert) { this->command(invert ? ILI9341_INVON : ILI9341_INVOFF); }
|
||||
|
||||
int ILI9341Display::get_width_internal() { return this->width_; }
|
||||
int ILI9341Display::get_height_internal() { return this->height_; }
|
||||
|
||||
uint32_t ILI9341Display::buffer_to_transfer_(uint32_t pos, uint32_t sz) {
|
||||
uint8_t *src = buffer_ + pos;
|
||||
uint8_t *dst = transfer_buffer_;
|
||||
|
||||
if (sz > sizeof(transfer_buffer_) / 2) {
|
||||
sz = sizeof(transfer_buffer_) / 2;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < sz; ++i) {
|
||||
uint16_t color;
|
||||
if (this->buffer_color_mode_ == BITS_8) {
|
||||
color = display::ColorUtil::color_to_565(display::ColorUtil::rgb332_to_color(*src++));
|
||||
} else { // if (this->buffer_color_mode == BITS_8_INDEXED) {
|
||||
Color col = display::ColorUtil::index8_to_color_palette888(*src++, this->palette_);
|
||||
color = display::ColorUtil::color_to_565(col);
|
||||
}
|
||||
*dst++ = (uint8_t)(color >> 8);
|
||||
*dst++ = (uint8_t) color;
|
||||
}
|
||||
|
||||
return sz;
|
||||
}
|
||||
|
||||
// M5Stack display
|
||||
void ILI9341M5Stack::initialize() {
|
||||
this->init_lcd_(INITCMD_M5STACK);
|
||||
this->width_ = 320;
|
||||
this->height_ = 240;
|
||||
this->invert_display_(true);
|
||||
}
|
||||
|
||||
// 24_TFT display
|
||||
void ILI9341TFT24::initialize() {
|
||||
this->init_lcd_(INITCMD_TFT);
|
||||
this->width_ = 240;
|
||||
this->height_ = 320;
|
||||
}
|
||||
|
||||
// 24_TFT rotated display
|
||||
void ILI9341TFT24R::initialize() {
|
||||
this->init_lcd_(INITCMD_TFT);
|
||||
this->width_ = 320;
|
||||
this->height_ = 240;
|
||||
}
|
||||
|
||||
} // namespace ili9341
|
||||
} // namespace esphome
|
|
@ -1,70 +0,0 @@
|
|||
#pragma once
|
||||
#include "esphome/core/helpers.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace ili9341 {
|
||||
|
||||
// clang-format off
|
||||
static const uint8_t PROGMEM INITCMD_M5STACK[] = {
|
||||
0xEF, 3, 0x03, 0x80, 0x02,
|
||||
0xCF, 3, 0x00, 0xC1, 0x30,
|
||||
0xED, 4, 0x64, 0x03, 0x12, 0x81,
|
||||
0xE8, 3, 0x85, 0x00, 0x78,
|
||||
0xCB, 5, 0x39, 0x2C, 0x00, 0x34, 0x02,
|
||||
0xF7, 1, 0x20,
|
||||
0xEA, 2, 0x00, 0x00,
|
||||
ILI9341_PWCTR1 , 1, 0x23, // Power control VRH[5:0]
|
||||
ILI9341_PWCTR2 , 1, 0x10, // Power control SAP[2:0];BT[3:0]
|
||||
ILI9341_VMCTR1 , 2, 0x3e, 0x28, // VCM control
|
||||
ILI9341_VMCTR2 , 1, 0x86, // VCM control2
|
||||
ILI9341_MADCTL , 1, MADCTL_BGR, // Memory Access Control
|
||||
ILI9341_VSCRSADD, 1, 0x00, // Vertical scroll zero
|
||||
ILI9341_PIXFMT , 1, 0x55,
|
||||
ILI9341_FRMCTR1 , 2, 0x00, 0x13,
|
||||
ILI9341_DFUNCTR , 3, 0x08, 0x82, 0x27, // Display Function Control
|
||||
0xF2, 1, 0x00, // 3Gamma Function Disable
|
||||
ILI9341_GAMMASET , 1, 0x01, // Gamma curve selected
|
||||
ILI9341_GMCTRP1 , 15, 0x0F, 0x31, 0x2B, 0x0C, 0x0E, 0x08, // Set Gamma
|
||||
0x4E, 0xF1, 0x37, 0x07, 0x10, 0x03,
|
||||
0x0E, 0x09, 0x00,
|
||||
ILI9341_GMCTRN1 , 15, 0x00, 0x0E, 0x14, 0x03, 0x11, 0x07, // Set Gamma
|
||||
0x31, 0xC1, 0x48, 0x08, 0x0F, 0x0C,
|
||||
0x31, 0x36, 0x0F,
|
||||
ILI9341_SLPOUT , 0x80, // Exit Sleep
|
||||
ILI9341_DISPON , 0x80, // Display on
|
||||
0x00 // End of list
|
||||
};
|
||||
|
||||
static const uint8_t PROGMEM INITCMD_TFT[] = {
|
||||
0xEF, 3, 0x03, 0x80, 0x02,
|
||||
0xCF, 3, 0x00, 0xC1, 0x30,
|
||||
0xED, 4, 0x64, 0x03, 0x12, 0x81,
|
||||
0xE8, 3, 0x85, 0x00, 0x78,
|
||||
0xCB, 5, 0x39, 0x2C, 0x00, 0x34, 0x02,
|
||||
0xF7, 1, 0x20,
|
||||
0xEA, 2, 0x00, 0x00,
|
||||
ILI9341_PWCTR1 , 1, 0x23, // Power control VRH[5:0]
|
||||
ILI9341_PWCTR2 , 1, 0x10, // Power control SAP[2:0];BT[3:0]
|
||||
ILI9341_VMCTR1 , 2, 0x3e, 0x28, // VCM control
|
||||
ILI9341_VMCTR2 , 1, 0x86, // VCM control2
|
||||
ILI9341_MADCTL , 1, 0x48, // Memory Access Control
|
||||
ILI9341_VSCRSADD, 1, 0x00, // Vertical scroll zero
|
||||
ILI9341_PIXFMT , 1, 0x55,
|
||||
ILI9341_FRMCTR1 , 2, 0x00, 0x18,
|
||||
ILI9341_DFUNCTR , 3, 0x08, 0x82, 0x27, // Display Function Control
|
||||
0xF2, 1, 0x00, // 3Gamma Function Disable
|
||||
ILI9341_GAMMASET , 1, 0x01, // Gamma curve selected
|
||||
ILI9341_GMCTRP1 , 15, 0x0F, 0x31, 0x2B, 0x0C, 0x0E, 0x08, // Set Gamma
|
||||
0x4E, 0xF1, 0x37, 0x07, 0x10, 0x03,
|
||||
0x0E, 0x09, 0x00,
|
||||
ILI9341_GMCTRN1 , 15, 0x00, 0x0E, 0x14, 0x03, 0x11, 0x07, // Set Gamma
|
||||
0x31, 0xC1, 0x48, 0x08, 0x0F, 0x0C,
|
||||
0x31, 0x36, 0x0F,
|
||||
ILI9341_SLPOUT , 0x80, // Exit Sleep
|
||||
ILI9341_DISPON , 0x80, // Display on
|
||||
0x00 // End of list
|
||||
};
|
||||
|
||||
// clang-format on
|
||||
} // namespace ili9341
|
||||
} // namespace esphome
|
0
esphome/components/ili9xxx/__init__.py
Normal file
0
esphome/components/ili9xxx/__init__.py
Normal file
159
esphome/components/ili9xxx/display.py
Normal file
159
esphome/components/ili9xxx/display.py
Normal file
|
@ -0,0 +1,159 @@
|
|||
import esphome.codegen as cg
|
||||
import esphome.config_validation as cv
|
||||
from esphome import core, pins
|
||||
from esphome.components import display, spi
|
||||
from esphome.core import CORE, HexInt
|
||||
from esphome.const import (
|
||||
CONF_COLOR_PALETTE,
|
||||
CONF_DC_PIN,
|
||||
CONF_ID,
|
||||
CONF_LAMBDA,
|
||||
CONF_MODEL,
|
||||
CONF_RAW_DATA_ID,
|
||||
CONF_PAGES,
|
||||
CONF_RESET_PIN,
|
||||
CONF_DIMENSIONS,
|
||||
)
|
||||
|
||||
DEPENDENCIES = ["spi"]
|
||||
AUTO_LOAD = ["psram"]
|
||||
|
||||
CODEOWNERS = ["@nielsnl68"]
|
||||
|
||||
ili9XXX_ns = cg.esphome_ns.namespace("ili9xxx")
|
||||
ili9XXXSPI = ili9XXX_ns.class_(
|
||||
"ILI9XXXDisplay", cg.PollingComponent, spi.SPIDevice, display.DisplayBuffer
|
||||
)
|
||||
|
||||
ILI9XXXColorMode = ili9XXX_ns.enum("ILI9XXXColorMode")
|
||||
|
||||
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),
|
||||
"ILI9486": ili9XXX_ns.class_("ILI9XXXILI9486", ili9XXXSPI),
|
||||
"ILI9488": ili9XXX_ns.class_("ILI9XXXILI9488", ili9XXXSPI),
|
||||
"ST7796": ili9XXX_ns.class_("ILI9XXXST7796", ili9XXXSPI),
|
||||
}
|
||||
|
||||
COLOR_PALETTE = cv.one_of("NONE", "GRAYSCALE", "IMAGE_ADAPTIVE")
|
||||
|
||||
CONF_LED_PIN = "led_pin"
|
||||
CONF_COLOR_PALETTE_IMAGES = "color_palette_images"
|
||||
|
||||
|
||||
def _validate(config):
|
||||
if config.get(CONF_COLOR_PALETTE) == "IMAGE_ADAPTIVE" and not config.get(
|
||||
CONF_COLOR_PALETTE_IMAGES
|
||||
):
|
||||
raise cv.Invalid(
|
||||
"Color palette in IMAGE_ADAPTIVE mode requires at least one 'color_palette_images' entry to generate palette"
|
||||
)
|
||||
if (
|
||||
config.get(CONF_COLOR_PALETTE_IMAGES)
|
||||
and config.get(CONF_COLOR_PALETTE) != "IMAGE_ADAPTIVE"
|
||||
):
|
||||
raise cv.Invalid(
|
||||
"Providing color palette images requires palette mode to be 'IMAGE_ADAPTIVE'"
|
||||
)
|
||||
return config
|
||||
|
||||
|
||||
CONFIG_SCHEMA = cv.All(
|
||||
display.FULL_DISPLAY_SCHEMA.extend(
|
||||
{
|
||||
cv.GenerateID(): cv.declare_id(ili9XXXSPI),
|
||||
cv.Required(CONF_MODEL): cv.enum(MODELS, upper=True, space="_"),
|
||||
cv.Optional(CONF_DIMENSIONS): cv.dimensions,
|
||||
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(
|
||||
"This property is removed. To use the backlight use proper light component."
|
||||
),
|
||||
cv.Optional(CONF_COLOR_PALETTE, default="NONE"): COLOR_PALETTE,
|
||||
cv.GenerateID(CONF_RAW_DATA_ID): cv.declare_id(cg.uint8),
|
||||
cv.Optional(CONF_COLOR_PALETTE_IMAGES, default=[]): cv.ensure_list(
|
||||
cv.file_
|
||||
),
|
||||
}
|
||||
)
|
||||
.extend(cv.polling_component_schema("1s"))
|
||||
.extend(spi.spi_device_schema(False)),
|
||||
cv.has_at_most_one_key(CONF_PAGES, CONF_LAMBDA),
|
||||
_validate,
|
||||
)
|
||||
|
||||
|
||||
async def to_code(config):
|
||||
rhs = MODELS[config[CONF_MODEL]].new()
|
||||
var = cg.Pvariable(config[CONF_ID], rhs)
|
||||
|
||||
await cg.register_component(var, config)
|
||||
await display.register_display(var, 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_LAMBDA in config:
|
||||
lambda_ = await cg.process_lambda(
|
||||
config[CONF_LAMBDA], [(display.DisplayBufferRef, "it")], return_type=cg.void
|
||||
)
|
||||
cg.add(var.set_writer(lambda_))
|
||||
|
||||
if CONF_RESET_PIN in config:
|
||||
reset = await cg.gpio_pin_expression(config[CONF_RESET_PIN])
|
||||
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])
|
||||
)
|
||||
|
||||
rhs = None
|
||||
if config[CONF_COLOR_PALETTE] == "GRAYSCALE":
|
||||
cg.add(var.set_buffer_color_mode(ILI9XXXColorMode.BITS_8_INDEXED))
|
||||
rhs = []
|
||||
for x in range(256):
|
||||
rhs.extend([HexInt(x), HexInt(x), HexInt(x)])
|
||||
prog_arr = cg.progmem_array(config[CONF_RAW_DATA_ID], rhs)
|
||||
cg.add(var.set_palette(prog_arr))
|
||||
elif config[CONF_COLOR_PALETTE] == "IMAGE_ADAPTIVE":
|
||||
cg.add(var.set_buffer_color_mode(ILI9XXXColorMode.BITS_8_INDEXED))
|
||||
from PIL import Image
|
||||
|
||||
def load_image(filename):
|
||||
path = CORE.relative_config_path(filename)
|
||||
try:
|
||||
return Image.open(path)
|
||||
except Exception as e:
|
||||
raise core.EsphomeError(f"Could not load image file {path}: {e}")
|
||||
|
||||
# make a wide horizontal combined image.
|
||||
images = [load_image(x) for x in config[CONF_COLOR_PALETTE_IMAGES]]
|
||||
total_width = sum(i.width for i in images)
|
||||
max_height = max(i.height for i in images)
|
||||
|
||||
ref_image = Image.new("RGB", (total_width, max_height))
|
||||
x = 0
|
||||
for i in images:
|
||||
ref_image.paste(i, (x, 0))
|
||||
x = x + i.width
|
||||
|
||||
# reduce the colors on combined image to 256.
|
||||
converted = ref_image.convert("P", palette=Image.ADAPTIVE, colors=256)
|
||||
# if you want to verify how the images look use
|
||||
# ref_image.save("ref_in.png")
|
||||
# converted.save("ref_out.png")
|
||||
palette = converted.getpalette()
|
||||
assert len(palette) == 256 * 3
|
||||
rhs = palette
|
||||
else:
|
||||
cg.add(var.set_buffer_color_mode(ILI9XXXColorMode.BITS_16))
|
||||
|
||||
if rhs is not None:
|
||||
prog_arr = cg.progmem_array(config[CONF_RAW_DATA_ID], rhs)
|
||||
cg.add(var.set_palette(prog_arr))
|
96
esphome/components/ili9xxx/ili9xxx_defines.h
Normal file
96
esphome/components/ili9xxx/ili9xxx_defines.h
Normal file
|
@ -0,0 +1,96 @@
|
|||
#pragma once
|
||||
|
||||
namespace esphome {
|
||||
namespace ili9xxx {
|
||||
|
||||
// Color definitions
|
||||
// clang-format off
|
||||
static const uint8_t MADCTL_MY = 0x80; ///< Bit 7 Bottom to top
|
||||
static const uint8_t MADCTL_MX = 0x40; ///< Bit 6 Right to left
|
||||
static const uint8_t MADCTL_MV = 0x20; ///< Bit 5 Reverse Mode
|
||||
static const uint8_t MADCTL_ML = 0x10; ///< Bit 4 LCD refresh Bottom to top
|
||||
static const uint8_t MADCTL_RGB = 0x00; ///< Bit 3 Red-Green-Blue pixel order
|
||||
static const uint8_t MADCTL_BGR = 0x08; ///< Bit 3 Blue-Green-Red pixel order
|
||||
static const uint8_t MADCTL_MH = 0x04; ///< Bit 2 LCD refresh right to left
|
||||
// clang-format on
|
||||
|
||||
// All ILI9XXX specific commands some are used by init()
|
||||
static const uint8_t ILI9XXX_NOP = 0x00;
|
||||
static const uint8_t ILI9XXX_SWRESET = 0x01;
|
||||
static const uint8_t ILI9XXX_RDDID = 0x04;
|
||||
static const uint8_t ILI9XXX_RDDST = 0x09;
|
||||
|
||||
static const uint8_t ILI9XXX_SLPIN = 0x10;
|
||||
static const uint8_t ILI9XXX_SLPOUT = 0x11;
|
||||
static const uint8_t ILI9XXX_PTLON = 0x12;
|
||||
static const uint8_t ILI9XXX_NORON = 0x13;
|
||||
|
||||
static const uint8_t ILI9XXX_RDMODE = 0x0A;
|
||||
static const uint8_t ILI9XXX_RDMADCTL = 0x0B;
|
||||
static const uint8_t ILI9XXX_RDPIXFMT = 0x0C;
|
||||
static const uint8_t ILI9XXX_RDIMGFMT = 0x0D;
|
||||
static const uint8_t ILI9XXX_RDSELFDIAG = 0x0F;
|
||||
|
||||
static const uint8_t ILI9XXX_INVOFF = 0x20;
|
||||
static const uint8_t ILI9XXX_INVON = 0x21;
|
||||
static const uint8_t ILI9XXX_GAMMASET = 0x26;
|
||||
static const uint8_t ILI9XXX_DISPOFF = 0x28;
|
||||
static const uint8_t ILI9XXX_DISPON = 0x29;
|
||||
|
||||
static const uint8_t ILI9XXX_CASET = 0x2A;
|
||||
static const uint8_t ILI9XXX_PASET = 0x2B;
|
||||
static const uint8_t ILI9XXX_RAMWR = 0x2C;
|
||||
static const uint8_t ILI9XXX_RAMRD = 0x2E;
|
||||
|
||||
static const uint8_t ILI9XXX_PTLAR = 0x30;
|
||||
static const uint8_t ILI9XXX_VSCRDEF = 0x33;
|
||||
static const uint8_t ILI9XXX_MADCTL = 0x36;
|
||||
static const uint8_t ILI9XXX_VSCRSADD = 0x37;
|
||||
static const uint8_t ILI9XXX_IDMOFF = 0x38;
|
||||
static const uint8_t ILI9XXX_IDMON = 0x39;
|
||||
static const uint8_t ILI9XXX_PIXFMT = 0x3A;
|
||||
static const uint8_t ILI9XXX_COLMOD = 0x3A;
|
||||
|
||||
static const uint8_t ILI9XXX_GETSCANLINE = 0x45;
|
||||
|
||||
static const uint8_t ILI9XXX_WRDISBV = 0x51;
|
||||
static const uint8_t ILI9XXX_RDDISBV = 0x52;
|
||||
static const uint8_t ILI9XXX_WRCTRLD = 0x53;
|
||||
|
||||
static const uint8_t ILI9XXX_IFMODE = 0xB0;
|
||||
static const uint8_t ILI9XXX_FRMCTR1 = 0xB1;
|
||||
static const uint8_t ILI9XXX_FRMCTR2 = 0xB2;
|
||||
static const uint8_t ILI9XXX_FRMCTR3 = 0xB3;
|
||||
static const uint8_t ILI9XXX_INVCTR = 0xB4;
|
||||
static const uint8_t ILI9XXX_DFUNCTR = 0xB6;
|
||||
static const uint8_t ILI9XXX_ETMOD = 0xB7;
|
||||
|
||||
static const uint8_t ILI9XXX_PWCTR1 = 0xC0;
|
||||
static const uint8_t ILI9XXX_PWCTR2 = 0xC1;
|
||||
static const uint8_t ILI9XXX_PWCTR3 = 0xC2;
|
||||
static const uint8_t ILI9XXX_PWCTR4 = 0xC3;
|
||||
static const uint8_t ILI9XXX_PWCTR5 = 0xC4;
|
||||
static const uint8_t ILI9XXX_VMCTR1 = 0xC5;
|
||||
static const uint8_t ILI9XXX_IFCTR = 0xC6;
|
||||
static const uint8_t ILI9XXX_VMCTR2 = 0xC7;
|
||||
static const uint8_t ILI9XXX_GMCTR = 0xC8;
|
||||
static const uint8_t ILI9XXX_SETEXTC = 0xC8;
|
||||
|
||||
static const uint8_t ILI9XXX_PWSET = 0xD0;
|
||||
static const uint8_t ILI9XXX_VMCTR = 0xD1;
|
||||
static const uint8_t ILI9XXX_PWSETN = 0xD2;
|
||||
static const uint8_t ILI9XXX_RDID4 = 0xD3;
|
||||
static const uint8_t ILI9XXX_RDINDEX = 0xD9;
|
||||
static const uint8_t ILI9XXX_RDID1 = 0xDA;
|
||||
static const uint8_t ILI9XXX_RDID2 = 0xDB;
|
||||
static const uint8_t ILI9XXX_RDID3 = 0xDC;
|
||||
static const uint8_t ILI9XXX_RDIDX = 0xDD; // TBC
|
||||
|
||||
static const uint8_t ILI9XXX_GMCTRP1 = 0xE0;
|
||||
static const uint8_t ILI9XXX_GMCTRN1 = 0xE1;
|
||||
|
||||
static const uint8_t ILI9XXX_CSCON = 0xF0;
|
||||
static const uint8_t ILI9XXX_ADJCTL3 = 0xF7;
|
||||
|
||||
} // namespace ili9xxx
|
||||
} // namespace esphome
|
416
esphome/components/ili9xxx/ili9xxx_display.cpp
Normal file
416
esphome/components/ili9xxx/ili9xxx_display.cpp
Normal file
|
@ -0,0 +1,416 @@
|
|||
#include "ili9xxx_display.h"
|
||||
#include "esphome/core/log.h"
|
||||
#include "esphome/core/application.h"
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/core/hal.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace ili9xxx {
|
||||
|
||||
static const char *const TAG = "ili9xxx";
|
||||
|
||||
void ILI9XXXDisplay::setup() {
|
||||
this->setup_pins_();
|
||||
this->initialize();
|
||||
|
||||
this->x_low_ = this->width_;
|
||||
this->y_low_ = this->height_;
|
||||
this->x_high_ = 0;
|
||||
this->y_high_ = 0;
|
||||
if (this->buffer_color_mode_ == BITS_16) {
|
||||
this->init_internal_(this->get_buffer_length_() * 2);
|
||||
if (this->buffer_ != nullptr) {
|
||||
return;
|
||||
}
|
||||
this->buffer_color_mode_ = BITS_8;
|
||||
}
|
||||
this->init_internal_(this->get_buffer_length_());
|
||||
if (this->buffer_ == nullptr) {
|
||||
this->mark_failed();
|
||||
}
|
||||
}
|
||||
|
||||
void ILI9XXXDisplay::setup_pins_() {
|
||||
this->dc_pin_->setup(); // OUTPUT
|
||||
this->dc_pin_->digital_write(false);
|
||||
if (this->reset_pin_ != nullptr) {
|
||||
this->reset_pin_->setup(); // OUTPUT
|
||||
this->reset_pin_->digital_write(true);
|
||||
}
|
||||
|
||||
this->spi_setup();
|
||||
|
||||
this->reset_();
|
||||
}
|
||||
|
||||
void ILI9XXXDisplay::dump_config() {
|
||||
LOG_DISPLAY("", "ili9xxx", this);
|
||||
switch (this->buffer_color_mode_) {
|
||||
case BITS_8_INDEXED:
|
||||
ESP_LOGCONFIG(TAG, " Color mode: 8bit Indexed");
|
||||
break;
|
||||
case BITS_16:
|
||||
ESP_LOGCONFIG(TAG, " Color mode: 16bit");
|
||||
break;
|
||||
default:
|
||||
ESP_LOGCONFIG(TAG, " Color mode: 8bit 332 mode");
|
||||
break;
|
||||
}
|
||||
if (this->is_18bitdisplay_) {
|
||||
ESP_LOGCONFIG(TAG, " 18-Bit Mode: YES");
|
||||
}
|
||||
|
||||
LOG_PIN(" Reset Pin: ", this->reset_pin_);
|
||||
LOG_PIN(" DC Pin: ", this->dc_pin_);
|
||||
LOG_PIN(" Busy Pin: ", this->busy_pin_);
|
||||
|
||||
if (this->is_failed()) {
|
||||
ESP_LOGCONFIG(TAG, " => Failed to init Memory: YES!");
|
||||
}
|
||||
LOG_UPDATE_INTERVAL(this);
|
||||
}
|
||||
|
||||
float ILI9XXXDisplay::get_setup_priority() const { return setup_priority::HARDWARE; }
|
||||
|
||||
void ILI9XXXDisplay::fill(Color color) {
|
||||
uint16_t new_color = 0;
|
||||
this->x_low_ = 0;
|
||||
this->y_low_ = 0;
|
||||
this->x_high_ = this->get_width_internal() - 1;
|
||||
this->y_high_ = this->get_height_internal() - 1;
|
||||
switch (this->buffer_color_mode_) {
|
||||
case BITS_8_INDEXED:
|
||||
new_color = display::ColorUtil::color_to_index8_palette888(color, this->palette_);
|
||||
break;
|
||||
case BITS_16:
|
||||
new_color = display::ColorUtil::color_to_565(color);
|
||||
for (uint32_t i = 0; i < this->get_buffer_length_() * 2; i = i + 2) {
|
||||
this->buffer_[i] = (uint8_t)(new_color >> 8);
|
||||
this->buffer_[i + 1] = (uint8_t) new_color;
|
||||
}
|
||||
return;
|
||||
break;
|
||||
default:
|
||||
new_color = display::ColorUtil::color_to_332(color, display::ColorOrder::COLOR_ORDER_RGB);
|
||||
break;
|
||||
}
|
||||
memset(this->buffer_, (uint8_t) new_color, this->get_buffer_length_());
|
||||
}
|
||||
|
||||
void HOT ILI9XXXDisplay::draw_absolute_pixel_internal(int x, int y, Color color) {
|
||||
if (x >= this->get_width_internal() || x < 0 || y >= this->get_height_internal() || y < 0) {
|
||||
return;
|
||||
}
|
||||
uint32_t pos = (y * width_) + x;
|
||||
uint16_t new_color;
|
||||
bool updated = false;
|
||||
switch (this->buffer_color_mode_) {
|
||||
case BITS_8_INDEXED:
|
||||
new_color = display::ColorUtil::color_to_index8_palette888(color, this->palette_);
|
||||
break;
|
||||
case BITS_16:
|
||||
pos = pos * 2;
|
||||
new_color = display::ColorUtil::color_to_565(color, display::ColorOrder::COLOR_ORDER_RGB);
|
||||
if (this->buffer_[pos] != (uint8_t)(new_color >> 8)) {
|
||||
this->buffer_[pos] = (uint8_t)(new_color >> 8);
|
||||
updated = true;
|
||||
}
|
||||
pos = pos + 1;
|
||||
new_color = new_color & 0xFF;
|
||||
break;
|
||||
default:
|
||||
new_color = display::ColorUtil::color_to_332(color, display::ColorOrder::COLOR_ORDER_RGB);
|
||||
break;
|
||||
}
|
||||
|
||||
if (this->buffer_[pos] != new_color) {
|
||||
this->buffer_[pos] = new_color;
|
||||
updated = true;
|
||||
}
|
||||
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_);
|
||||
}
|
||||
}
|
||||
|
||||
void ILI9XXXDisplay::update() {
|
||||
if (this->prossing_update_) {
|
||||
this->need_update_ = true;
|
||||
return;
|
||||
}
|
||||
do {
|
||||
this->prossing_update_ = true;
|
||||
this->need_update_ = false;
|
||||
if (!this->need_update_) {
|
||||
this->do_update_();
|
||||
}
|
||||
} while (this->need_update_);
|
||||
this->prossing_update_ = false;
|
||||
this->display_();
|
||||
}
|
||||
|
||||
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_);
|
||||
|
||||
// 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);
|
||||
|
||||
ESP_LOGV(TAG,
|
||||
"Start display(xlow:%d, ylow:%d, xhigh:%d, yhigh:%d, width:%d, "
|
||||
"heigth:%d, start_pos:%d)",
|
||||
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);
|
||||
}
|
||||
pos += sz;
|
||||
rem -= sz;
|
||||
}
|
||||
App.feed_wdt();
|
||||
}
|
||||
this->end_data_();
|
||||
|
||||
// invalidate watermarks
|
||||
this->x_low_ = this->width_;
|
||||
this->y_low_ = this->height_;
|
||||
this->x_high_ = 0;
|
||||
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(); }
|
||||
|
||||
void ILI9XXXDisplay::command(uint8_t value) {
|
||||
this->start_command_();
|
||||
this->write_byte(value);
|
||||
this->end_command_();
|
||||
}
|
||||
|
||||
void ILI9XXXDisplay::data(uint8_t value) {
|
||||
this->start_data_();
|
||||
this->write_byte(value);
|
||||
this->end_data_();
|
||||
}
|
||||
|
||||
void ILI9XXXDisplay::send_command(uint8_t command_byte, const uint8_t *data_bytes, uint8_t num_data_bytes) {
|
||||
this->command(command_byte); // Send the command byte
|
||||
this->start_data_();
|
||||
this->write_array(data_bytes, num_data_bytes);
|
||||
this->end_data_();
|
||||
}
|
||||
|
||||
uint8_t ILI9XXXDisplay::read_command(uint8_t command_byte, uint8_t index) {
|
||||
uint8_t data = 0x10 + index;
|
||||
this->send_command(0xD9, &data, 1); // Set Index Register
|
||||
uint8_t result;
|
||||
this->start_command_();
|
||||
this->write_byte(command_byte);
|
||||
this->start_data_();
|
||||
do {
|
||||
result = this->read_byte();
|
||||
} while (index--);
|
||||
this->end_data_();
|
||||
return result;
|
||||
}
|
||||
|
||||
void ILI9XXXDisplay::start_command_() {
|
||||
this->dc_pin_->digital_write(false);
|
||||
this->enable();
|
||||
}
|
||||
void ILI9XXXDisplay::start_data_() {
|
||||
this->dc_pin_->digital_write(true);
|
||||
this->enable();
|
||||
}
|
||||
|
||||
void ILI9XXXDisplay::end_command_() { this->disable(); }
|
||||
void ILI9XXXDisplay::end_data_() { this->disable(); }
|
||||
|
||||
void ILI9XXXDisplay::reset_() {
|
||||
if (this->reset_pin_ != nullptr) {
|
||||
this->reset_pin_->digital_write(false);
|
||||
delay(10);
|
||||
this->reset_pin_->digital_write(true);
|
||||
delay(10);
|
||||
}
|
||||
}
|
||||
|
||||
void ILI9XXXDisplay::init_lcd_(const uint8_t *init_cmd) {
|
||||
uint8_t cmd, x, num_args;
|
||||
const uint8_t *addr = init_cmd;
|
||||
while ((cmd = progmem_read_byte(addr++)) > 0) {
|
||||
x = progmem_read_byte(addr++);
|
||||
num_args = x & 0x7F;
|
||||
send_command(cmd, addr, num_args);
|
||||
addr += num_args;
|
||||
if (x & 0x80)
|
||||
delay(150); // NOLINT
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
void ILI9XXXDisplay::invert_display_(bool invert) { this->command(invert ? ILI9XXX_INVON : ILI9XXX_INVOFF); }
|
||||
|
||||
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->invert_display_(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->invert_display_(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;
|
||||
}
|
||||
}
|
||||
|
||||
// 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 ILI9XXXST7796::initialize() {
|
||||
this->init_lcd_(INITCMD_ST7796);
|
||||
if (this->width_ == 0) {
|
||||
this->width_ = 320;
|
||||
}
|
||||
if (this->height_ == 0) {
|
||||
this->height_ = 480;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ili9xxx
|
||||
} // namespace esphome
|
|
@ -1,27 +1,21 @@
|
|||
#pragma once
|
||||
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/components/spi/spi.h"
|
||||
#include "esphome/components/display/display_buffer.h"
|
||||
#include "ili9341_defines.h"
|
||||
#include "ili9341_init.h"
|
||||
#include "esphome/core/log.h"
|
||||
#include "ili9xxx_defines.h"
|
||||
#include "ili9xxx_init.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace ili9341 {
|
||||
namespace ili9xxx {
|
||||
|
||||
enum ILI9341Model {
|
||||
M5STACK = 0,
|
||||
TFT_24,
|
||||
TFT_24R,
|
||||
const uint32_t ILI9XXX_TRANSFER_BUFFER_SIZE = 64;
|
||||
|
||||
enum ILI9XXXColorMode {
|
||||
BITS_8 = 0x08,
|
||||
BITS_8_INDEXED = 0x09,
|
||||
BITS_16 = 0x10,
|
||||
};
|
||||
|
||||
enum ILI9341ColorMode {
|
||||
BITS_8,
|
||||
BITS_8_INDEXED,
|
||||
};
|
||||
|
||||
class ILI9341Display : public PollingComponent,
|
||||
class ILI9XXXDisplay : public PollingComponent,
|
||||
public display::DisplayBuffer,
|
||||
public spi::SPIDevice<spi::BIT_ORDER_MSB_FIRST, spi::CLOCK_POLARITY_LOW,
|
||||
spi::CLOCK_PHASE_LEADING, spi::DATA_RATE_40MHZ> {
|
||||
|
@ -29,59 +23,46 @@ class ILI9341Display : public PollingComponent,
|
|||
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_led_pin(GPIOPin *led) { this->led_pin_ = led; }
|
||||
void set_model(ILI9341Model model) { this->model_ = model; }
|
||||
void set_palette(const uint8_t *palette) { this->palette_ = palette; }
|
||||
void set_buffer_color_mode(ILI9341ColorMode color_mode) { this->buffer_color_mode_ = color_mode; }
|
||||
|
||||
void set_buffer_color_mode(ILI9XXXColorMode color_mode) { this->buffer_color_mode_ = color_mode; }
|
||||
void set_dimentions(int16_t width, int16_t height) {
|
||||
this->height_ = height;
|
||||
this->width_ = width;
|
||||
}
|
||||
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);
|
||||
virtual void initialize() = 0;
|
||||
|
||||
void update() override;
|
||||
|
||||
void fill(Color color) override;
|
||||
|
||||
void dump_config() override;
|
||||
void setup() override {
|
||||
this->setup_pins_();
|
||||
this->initialize();
|
||||
|
||||
this->x_low_ = this->width_;
|
||||
this->y_low_ = this->height_;
|
||||
this->x_high_ = 0;
|
||||
this->y_high_ = 0;
|
||||
|
||||
this->init_internal_(this->get_buffer_length_());
|
||||
this->fill_internal_(0x00);
|
||||
}
|
||||
void setup() override;
|
||||
|
||||
display::DisplayType get_display_type() override { return display::DisplayType::DISPLAY_TYPE_COLOR; }
|
||||
|
||||
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 invert_display_(bool invert);
|
||||
void reset_();
|
||||
void fill_internal_(uint8_t color);
|
||||
void display_();
|
||||
void rotate_my_(uint8_t m);
|
||||
|
||||
ILI9341Model model_;
|
||||
int16_t width_{320}; ///< Display width as modified by current rotation
|
||||
int16_t height_{240}; ///< Display height as modified by current rotation
|
||||
int16_t width_{0}; ///< Display width as modified by current rotation
|
||||
int16_t height_{0}; ///< Display height as modified by current rotation
|
||||
uint16_t x_low_{0};
|
||||
uint16_t y_low_{0};
|
||||
uint16_t x_high_{0};
|
||||
uint16_t y_high_{0};
|
||||
const uint8_t *palette_;
|
||||
|
||||
ILI9341ColorMode buffer_color_mode_{BITS_8};
|
||||
ILI9XXXColorMode buffer_color_mode_{BITS_16};
|
||||
|
||||
uint32_t get_buffer_length_();
|
||||
int get_width_internal() override;
|
||||
|
@ -92,33 +73,66 @@ class ILI9341Display : public PollingComponent,
|
|||
void start_data_();
|
||||
void end_data_();
|
||||
|
||||
uint8_t transfer_buffer_[64];
|
||||
uint16_t transfer_buffer_[ILI9XXX_TRANSFER_BUFFER_SIZE];
|
||||
|
||||
uint32_t buffer_to_transfer_(uint32_t pos, uint32_t sz);
|
||||
|
||||
GPIOPin *reset_pin_{nullptr};
|
||||
GPIOPin *led_pin_{nullptr};
|
||||
GPIOPin *dc_pin_;
|
||||
GPIOPin *dc_pin_{nullptr};
|
||||
GPIOPin *busy_pin_{nullptr};
|
||||
|
||||
bool prossing_update_ = false;
|
||||
bool need_update_ = false;
|
||||
bool is_18bitdisplay_ = false;
|
||||
};
|
||||
|
||||
//----------- M5Stack display --------------
|
||||
class ILI9341M5Stack : public ILI9341Display {
|
||||
public:
|
||||
class ILI9XXXM5Stack : public ILI9XXXDisplay {
|
||||
protected:
|
||||
void initialize() override;
|
||||
};
|
||||
|
||||
//----------- ILI9341_24_TFT display --------------
|
||||
class ILI9341TFT24 : public ILI9341Display {
|
||||
public:
|
||||
//----------- M5Stack display --------------
|
||||
class ILI9XXXM5CORE : public ILI9XXXDisplay {
|
||||
protected:
|
||||
void initialize() override;
|
||||
};
|
||||
|
||||
//----------- ILI9341_24_TFT rotated display --------------
|
||||
class ILI9341TFT24R : public ILI9341Display {
|
||||
public:
|
||||
//----------- ILI9XXX_24_TFT display --------------
|
||||
class ILI9XXXILI9341 : public ILI9XXXDisplay {
|
||||
protected:
|
||||
void initialize() override;
|
||||
};
|
||||
|
||||
} // namespace ili9341
|
||||
//----------- ILI9XXX_24_TFT rotated display --------------
|
||||
class ILI9XXXILI9342 : public ILI9XXXDisplay {
|
||||
protected:
|
||||
void initialize() override;
|
||||
};
|
||||
|
||||
//----------- ILI9XXX_??_TFT rotated display --------------
|
||||
class ILI9XXXILI9481 : public ILI9XXXDisplay {
|
||||
protected:
|
||||
void initialize() override;
|
||||
};
|
||||
|
||||
//----------- ILI9XXX_35_TFT rotated display --------------
|
||||
class ILI9XXXILI9486 : public ILI9XXXDisplay {
|
||||
protected:
|
||||
void initialize() override;
|
||||
};
|
||||
|
||||
//----------- ILI9XXX_35_TFT rotated display --------------
|
||||
class ILI9XXXILI9488 : public ILI9XXXDisplay {
|
||||
protected:
|
||||
void initialize() override;
|
||||
};
|
||||
|
||||
//----------- ILI9XXX_35_TFT rotated display --------------
|
||||
class ILI9XXXST7796 : public ILI9XXXDisplay {
|
||||
protected:
|
||||
void initialize() override;
|
||||
};
|
||||
|
||||
} // namespace ili9xxx
|
||||
} // namespace esphome
|
174
esphome/components/ili9xxx/ili9xxx_init.h
Normal file
174
esphome/components/ili9xxx/ili9xxx_init.h
Normal file
|
@ -0,0 +1,174 @@
|
|||
#pragma once
|
||||
#include "esphome/core/helpers.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace ili9xxx {
|
||||
|
||||
// clang-format off
|
||||
static const uint8_t PROGMEM INITCMD_M5STACK[] = {
|
||||
0xEF, 3, 0x03, 0x80, 0x02,
|
||||
0xCF, 3, 0x00, 0xC1, 0x30,
|
||||
0xED, 4, 0x64, 0x03, 0x12, 0x81,
|
||||
0xE8, 3, 0x85, 0x00, 0x78,
|
||||
0xCB, 5, 0x39, 0x2C, 0x00, 0x34, 0x02,
|
||||
0xF7, 1, 0x20,
|
||||
0xEA, 2, 0x00, 0x00,
|
||||
ILI9XXX_PWCTR1 , 1, 0x23, // Power control VRH[5:0]
|
||||
ILI9XXX_PWCTR2 , 1, 0x10, // Power control SAP[2:0];BT[3:0]
|
||||
ILI9XXX_VMCTR1 , 2, 0x3e, 0x28, // VCM control
|
||||
ILI9XXX_VMCTR2 , 1, 0x86, // VCM control2
|
||||
ILI9XXX_MADCTL , 1, MADCTL_BGR, // Memory Access Control
|
||||
ILI9XXX_VSCRSADD, 1, 0x00, // Vertical scroll zero
|
||||
ILI9XXX_PIXFMT , 1, 0x55,
|
||||
ILI9XXX_FRMCTR1 , 2, 0x00, 0x13,
|
||||
ILI9XXX_DFUNCTR , 3, 0x08, 0x82, 0x27, // Display Function Control
|
||||
0xF2, 1, 0x00, // 3Gamma Function Disable
|
||||
ILI9XXX_GAMMASET , 1, 0x01, // Gamma curve selected
|
||||
ILI9XXX_GMCTRP1 , 15, 0x0F, 0x31, 0x2B, 0x0C, 0x0E, 0x08, // Set Gamma
|
||||
0x4E, 0xF1, 0x37, 0x07, 0x10, 0x03,
|
||||
0x0E, 0x09, 0x00,
|
||||
ILI9XXX_GMCTRN1 , 15, 0x00, 0x0E, 0x14, 0x03, 0x11, 0x07, // Set Gamma
|
||||
0x31, 0xC1, 0x48, 0x08, 0x0F, 0x0C,
|
||||
0x31, 0x36, 0x0F,
|
||||
ILI9XXX_SLPOUT , 0x80, // Exit Sleep
|
||||
ILI9XXX_DISPON , 0x80, // Display on
|
||||
0x00 // End of list
|
||||
};
|
||||
|
||||
static const uint8_t PROGMEM INITCMD_M5CORE[] = {
|
||||
ILI9XXX_SETEXTC, 3, 0xFF,0x93,0x42, // Turn on the external command
|
||||
ILI9XXX_PWCTR1 , 2, 0x12, 0x12,
|
||||
ILI9XXX_PWCTR2 , 1, 0x03,
|
||||
ILI9XXX_VMCTR1 , 1, 0xF2,
|
||||
ILI9XXX_IFMODE , 1, 0xE0,
|
||||
0xF6 , 3, 0x01, 0x00, 0x00,
|
||||
ILI9XXX_GMCTRP1,15, 0x00,0x0C,0x11,0x04,0x11,0x08,0x37,0x89,0x4C,0x06,0x0C,0x0A,0x2E,0x34,0x0F,
|
||||
ILI9XXX_GMCTRN1,15, 0x00,0x0B,0x11,0x05,0x13,0x09,0x33,0x67,0x48,0x07,0x0E,0x0B,0x2E,0x33,0x0F,
|
||||
ILI9XXX_DFUNCTR, 4, 0x08,0x82,0x1D,0x04,
|
||||
ILI9XXX_IDMOFF , 0,
|
||||
ILI9XXX_DISPON , 0x80, // Display on
|
||||
ILI9XXX_SLPOUT , 0x80, // Exit Sleep
|
||||
|
||||
0x00 // End of list
|
||||
};
|
||||
|
||||
|
||||
|
||||
static const uint8_t PROGMEM INITCMD_ILI9341[] = {
|
||||
0xEF, 3, 0x03, 0x80, 0x02,
|
||||
0xCF, 3, 0x00, 0xC1, 0x30,
|
||||
0xED, 4, 0x64, 0x03, 0x12, 0x81,
|
||||
0xE8, 3, 0x85, 0x00, 0x78,
|
||||
0xCB, 5, 0x39, 0x2C, 0x00, 0x34, 0x02,
|
||||
0xF7, 1, 0x20,
|
||||
0xEA, 2, 0x00, 0x00,
|
||||
ILI9XXX_PWCTR1 , 1, 0x23, // Power control VRH[5:0]
|
||||
ILI9XXX_PWCTR2 , 1, 0x10, // Power control SAP[2:0];BT[3:0]
|
||||
ILI9XXX_VMCTR1 , 2, 0x3e, 0x28, // VCM control
|
||||
ILI9XXX_VMCTR2 , 1, 0x86, // VCM control2
|
||||
ILI9XXX_MADCTL , 1, 0x48, // Memory Access Control
|
||||
ILI9XXX_VSCRSADD, 1, 0x00, // Vertical scroll zero
|
||||
ILI9XXX_PIXFMT , 1, 0x55,
|
||||
ILI9XXX_FRMCTR1 , 2, 0x00, 0x18,
|
||||
ILI9XXX_DFUNCTR , 3, 0x08, 0x82, 0x27, // Display Function Control
|
||||
0xF2, 1, 0x00, // 3Gamma Function Disable
|
||||
ILI9XXX_GAMMASET , 1, 0x01, // Gamma curve selected
|
||||
ILI9XXX_GMCTRP1 , 15, 0x0F, 0x31, 0x2B, 0x0C, 0x0E, 0x08, // Set Gamma
|
||||
0x4E, 0xF1, 0x37, 0x07, 0x10, 0x03,
|
||||
0x0E, 0x09, 0x00,
|
||||
ILI9XXX_GMCTRN1 , 15, 0x00, 0x0E, 0x14, 0x03, 0x11, 0x07, // Set Gamma
|
||||
0x31, 0xC1, 0x48, 0x08, 0x0F, 0x0C,
|
||||
0x31, 0x36, 0x0F,
|
||||
ILI9XXX_SLPOUT , 0x80, // Exit Sleep
|
||||
ILI9XXX_DISPON , 0x80, // Display on
|
||||
0x00 // End of list
|
||||
};
|
||||
|
||||
static const uint8_t PROGMEM INITCMD_ILI9481[] = {
|
||||
ILI9XXX_SLPOUT , 0x80, // Exit sleep mode
|
||||
ILI9XXX_PWSET , 3, 0x07, 0x41, 0x1D,
|
||||
ILI9XXX_VMCTR , 3, 0x00, 0x1C, 0x1F,
|
||||
ILI9XXX_PWSETN , 2, 0x01, 0x11,
|
||||
ILI9XXX_PWCTR1 , 5, 0x10, 0x3B, 0x00, 0x02, 0x11,
|
||||
ILI9XXX_VMCTR1 , 1, 0x03,
|
||||
ILI9XXX_IFCTR , 1, 0x83,
|
||||
ILI9XXX_GMCTR ,12, 0x00, 0x26, 0x21, 0x00, 0x00, 0x1F, 0x65, 0x23, 0x77, 0x00, 0x0F, 0x00,
|
||||
ILI9XXX_IFMODE , 1, 0x00, // CommandAccessProtect
|
||||
0xE4 , 1, 0xA0,
|
||||
ILI9XXX_CSCON , 1, 0x01,
|
||||
ILI9XXX_DISPON, 0x80, // Set display on
|
||||
0x00 // end
|
||||
};
|
||||
|
||||
static const uint8_t PROGMEM INITCMD_ILI9486[] = {
|
||||
ILI9XXX_SLPOUT, 0x80,
|
||||
ILI9XXX_PIXFMT, 1, 0x55,
|
||||
ILI9XXX_PWCTR3, 1, 0x44,
|
||||
ILI9XXX_VMCTR1, 4, 0x00, 0x00, 0x00, 0x00,
|
||||
ILI9XXX_GMCTRP1, 15, 0x0f,0x1f,0x1c,0x0c,0x0f,0x08,0x48,0x98,0x37,0x0a,0x13,0x04,0x11,0x0d,0x00,
|
||||
ILI9XXX_GMCTRN1, 15, 0x0f,0x32,0x2e,0x0b,0x0d,0x05,0x47,0x75,0x37,0x06,0x10,0x03,0x24,0x20,0x00,
|
||||
ILI9XXX_INVOFF, 0x80,
|
||||
ILI9XXX_MADCTL, 1, 0x48,
|
||||
ILI9XXX_DISPON, 0x80,
|
||||
|
||||
// ILI9XXX_MADCTL, 1, MADCTL_BGR | MADCTL_MV, //hardware rotation
|
||||
0x00 // End of list
|
||||
};
|
||||
|
||||
static const uint8_t PROGMEM INITCMD_ILI9488[] = {
|
||||
ILI9XXX_GMCTRP1,15, 0x00, 0x03, 0x09, 0x08, 0x16, 0x0A, 0x3F, 0x78, 0x4C, 0x09, 0x0A, 0x08, 0x16, 0x1A, 0x0F,
|
||||
ILI9XXX_GMCTRN1,15, 0x00, 0x16, 0x19, 0x03, 0x0F, 0x05, 0x32, 0x45, 0x46, 0x04, 0x0E, 0x0D, 0x35, 0x37, 0x0F,
|
||||
|
||||
ILI9XXX_PWCTR1, 2, 0x17, 0x15, // VRH1 VRH2
|
||||
ILI9XXX_PWCTR2, 1, 0x41, // VGH, VGL
|
||||
ILI9XXX_VMCTR1, 3, 0x00, 0x12, 0x80, // nVM VCM_REG VCM_REG_EN
|
||||
|
||||
ILI9XXX_IFMODE, 1, 0x00,
|
||||
ILI9XXX_FRMCTR1, 1, 0xA0, // Frame rate = 60Hz
|
||||
ILI9XXX_INVCTR, 1, 0x02, // Display Inversion Control = 2dot
|
||||
|
||||
ILI9XXX_DFUNCTR, 2, 0x02, 0x02, // Nomal scan
|
||||
|
||||
0xE9, 1, 0x00, // Set Image Functio. Disable 24 bit data
|
||||
|
||||
ILI9XXX_ADJCTL3, 4, 0xA9, 0x51, 0x2C, 0x82, // Adjust Control 3
|
||||
|
||||
ILI9XXX_MADCTL, 1, 0x28,
|
||||
//ILI9XXX_PIXFMT, 1, 0x55, // Interface Pixel Format = 16bit
|
||||
ILI9XXX_PIXFMT, 1, 0x66, //ILI9488 only supports 18-bit pixel format in 4/3 wire SPI mode
|
||||
|
||||
|
||||
|
||||
// 5 frames
|
||||
//ILI9XXX_ETMOD, 1, 0xC6, //
|
||||
|
||||
|
||||
ILI9XXX_SLPOUT, 0x80, // Exit sleep mode
|
||||
//ILI9XXX_INVON , 0,
|
||||
ILI9XXX_DISPON, 0x80, // Set display on
|
||||
0x00 // end
|
||||
};
|
||||
|
||||
static const uint8_t PROGMEM INITCMD_ST7796[] = {
|
||||
// This ST7796S initilization routine was copied from https://github.com/prenticedavid/Adafruit_ST7796S_kbv/blob/master/Adafruit_ST7796S_kbv.cpp
|
||||
ILI9XXX_SWRESET, 0x80, // Soft reset, then delay 150 ms
|
||||
ILI9XXX_CSCON, 1, 0xC3, // ?? Unlock Manufacturer
|
||||
ILI9XXX_CSCON, 1, 0x96,
|
||||
ILI9XXX_VMCTR1, 1, 0x1C, //VCOM Control 1 [1C]
|
||||
ILI9XXX_MADCTL, 1, 0x48, //Memory Access [00]
|
||||
ILI9XXX_PIXFMT, 1, 0x55, //565
|
||||
ILI9XXX_IFMODE, 1, 0x80, //Interface [00]
|
||||
ILI9XXX_INVCTR, 1, 0x01, //Inversion Control [01]
|
||||
ILI9XXX_DFUNCTR, 3, 0x80, 0x02, 0x3B, // Display Function Control [80 02 3B] .kbv SS=1, NL=480
|
||||
ILI9XXX_ETMOD, 1, 0xC6, //Entry Mode [06]
|
||||
|
||||
ILI9XXX_CSCON, 1, 0x69, //?? lock manufacturer commands
|
||||
ILI9XXX_CSCON, 1, 0x3C, //
|
||||
ILI9XXX_SLPOUT, 0x80, // Exit Sleep, then delay 150 ms
|
||||
ILI9XXX_DISPON, 0x80, // Main screen turn on, delay 150 ms
|
||||
0x00 // End of list
|
||||
};
|
||||
|
||||
// clang-format on
|
||||
} // namespace ili9xxx
|
||||
} // namespace esphome
|
|
@ -2693,24 +2693,18 @@ display:
|
|||
row_start: 0
|
||||
lambda: |-
|
||||
it.rectangle(0, 0, it.get_width(), it.get_height());
|
||||
- platform: ili9341
|
||||
- platform: ili9xxx
|
||||
model: TFT 2.4
|
||||
cs_pin: GPIO5
|
||||
dc_pin: GPIO4
|
||||
reset_pin: GPIO22
|
||||
led_pin:
|
||||
number: GPIO15
|
||||
inverted: true
|
||||
lambda: |-
|
||||
it.rectangle(0, 0, it.get_width(), it.get_height());
|
||||
- platform: ili9341
|
||||
- platform: ili9xxx
|
||||
model: TFT 2.4
|
||||
cs_pin: GPIO5
|
||||
dc_pin: GPIO4
|
||||
reset_pin: GPIO22
|
||||
led_pin:
|
||||
number: GPIO15
|
||||
inverted: true
|
||||
auto_clear_enabled: false
|
||||
rotation: 90
|
||||
lambda: |-
|
||||
|
|
Loading…
Reference in a new issue