mirror of
https://github.com/esphome/esphome.git
synced 2024-11-21 22:48:10 +01:00
add Ili9341 display (#1233)
* setup ili9341 framework used epaper-waveshare as start * first version working * added models for now only M5Stack * get_buffer_length is huge * fill, low/high watermark, buffer tests failed. RAM is to small for ili9341 16 bit color mode * removed high/low watermark debug log * added standard 2.4" TFT model * code cleanup * make ledpin optional busy pin is not needed * make bufer 1 byte to avoid the buffer allocation error * gitignore * added backlight pin to dump_config * huge speed increase 8bit color framebuffer (256 colors) lo and high watermark for drawing to screen * fix for images * higher spi data rates * Set spi data rate to 40Mhz Experimental * fixed: formatting fixed: the last row and column being trimmed fixed: namings * Update the code to use Color class * fixed minor color things * fixed linting * #patch minor fixes * fix gitignore too * Update esphome/components/ili9341/ili9341_display.cpp Co-authored-by: Oleg <epushiron+github@gmail.com> * reverting the changes as it's being fixed in PR-1241 Co-authored-by: Michiel van Turnhout <qris.online@gmail.com> Co-authored-by: Michiel van Turnhout <m.vanturnhout@exxellence.nl> Co-authored-by: Oleg <epushiron+github@gmail.com>
This commit is contained in:
parent
fc01a70b65
commit
9816e677a6
8 changed files with 549 additions and 0 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -119,3 +119,4 @@ config/
|
||||||
tests/build/
|
tests/build/
|
||||||
tests/.esphome/
|
tests/.esphome/
|
||||||
/.temp-clang-tidy.cpp
|
/.temp-clang-tidy.cpp
|
||||||
|
.pio/
|
||||||
|
|
0
esphome/components/ili9341/__init__.py
Normal file
0
esphome/components/ili9341/__init__.py
Normal file
61
esphome/components/ili9341/display.py
Normal file
61
esphome/components/ili9341/display.py
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
import esphome.codegen as cg
|
||||||
|
import esphome.config_validation as cv
|
||||||
|
from esphome import pins
|
||||||
|
from esphome.components import display, spi
|
||||||
|
from esphome.const import CONF_DC_PIN, \
|
||||||
|
CONF_ID, CONF_LAMBDA, CONF_MODEL, CONF_PAGES, CONF_RESET_PIN
|
||||||
|
|
||||||
|
DEPENDENCIES = ['spi']
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
ILI9341Model = ili9341_ns.enum('ILI9341Model')
|
||||||
|
|
||||||
|
MODELS = {
|
||||||
|
'M5STACK': ILI9341Model.M5STACK,
|
||||||
|
'TFT_2.4': ILI9341Model.TFT_24,
|
||||||
|
}
|
||||||
|
|
||||||
|
ILI9341_MODEL = cv.enum(MODELS, upper=True, space="_")
|
||||||
|
|
||||||
|
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,
|
||||||
|
}).extend(cv.polling_component_schema('1s')).extend(spi.spi_device_schema()),
|
||||||
|
cv.has_at_most_one_key(CONF_PAGES, CONF_LAMBDA))
|
||||||
|
|
||||||
|
|
||||||
|
def to_code(config):
|
||||||
|
if config[CONF_MODEL] == 'M5STACK':
|
||||||
|
lcd_type = ILI9341M5Stack
|
||||||
|
if config[CONF_MODEL] == 'TFT_2.4':
|
||||||
|
lcd_type = ILI9341TFT24
|
||||||
|
rhs = lcd_type.new()
|
||||||
|
var = cg.Pvariable(config[CONF_ID], rhs)
|
||||||
|
|
||||||
|
yield cg.register_component(var, config)
|
||||||
|
yield display.register_display(var, config)
|
||||||
|
yield spi.register_spi_device(var, config)
|
||||||
|
cg.add(var.set_model(config[CONF_MODEL]))
|
||||||
|
dc = yield cg.gpio_pin_expression(config[CONF_DC_PIN])
|
||||||
|
cg.add(var.set_dc_pin(dc))
|
||||||
|
|
||||||
|
if CONF_LAMBDA in config:
|
||||||
|
lambda_ = yield 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 = yield cg.gpio_pin_expression(config[CONF_RESET_PIN])
|
||||||
|
cg.add(var.set_reset_pin(reset))
|
||||||
|
if CONF_LED_PIN in config:
|
||||||
|
led_pin = yield cg.gpio_pin_expression(config[CONF_LED_PIN])
|
||||||
|
cg.add(var.set_led_pin(led_pin))
|
83
esphome/components/ili9341/ili9341_defines.h
Normal file
83
esphome/components/ili9341/ili9341_defines.h
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
#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
|
240
esphome/components/ili9341/ili9341_display.cpp
Normal file
240
esphome/components/ili9341/ili9341_display.cpp
Normal file
|
@ -0,0 +1,240 @@
|
||||||
|
#include "ili9341_display.h"
|
||||||
|
#include "esphome/core/log.h"
|
||||||
|
#include "esphome/core/application.h"
|
||||||
|
#include "esphome/core/helpers.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace ili9341 {
|
||||||
|
|
||||||
|
static const char *TAG = "ili9341";
|
||||||
|
|
||||||
|
void ILI9341Display::setup_pins_() {
|
||||||
|
this->init_internal_(this->get_buffer_length_());
|
||||||
|
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);
|
||||||
|
ESP_LOGCONFIG(TAG, " Width: %d, Height: %d, Rotation: %d", this->width_, this->height_, this->rotation_);
|
||||||
|
LOG_PIN(" Reset Pin: ", this->reset_pin_);
|
||||||
|
LOG_PIN(" DC Pin: ", this->dc_pin_);
|
||||||
|
LOG_PIN(" Busy Pin: ", this->busy_pin_);
|
||||||
|
LOG_PIN(" Backlight Pin: ", this->led_pin_);
|
||||||
|
LOG_UPDATE_INTERVAL(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
float ILI9341Display::get_setup_priority() const { return setup_priority::PROCESSOR; }
|
||||||
|
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
|
||||||
|
int w = this->x_high_ - this->x_low_ + 1;
|
||||||
|
int h = this->y_high_ - this->y_low_ + 1;
|
||||||
|
|
||||||
|
set_addr_window_(this->x_low_, this->y_low_, w, h);
|
||||||
|
this->start_data_();
|
||||||
|
uint32_t start_pos = ((this->y_low_ * this->width_) + x_low_);
|
||||||
|
for (uint16_t row = 0; row < h; row++) {
|
||||||
|
for (uint16_t col = 0; col < w; col++) {
|
||||||
|
uint32_t pos = start_pos + (row * width_) + col;
|
||||||
|
|
||||||
|
uint16_t color = convert_to_16bit_color_(buffer_[pos]);
|
||||||
|
this->write_byte(color >> 8);
|
||||||
|
this->write_byte(color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this->end_data_();
|
||||||
|
|
||||||
|
// invalidate watermarks
|
||||||
|
this->x_low_ = this->width_;
|
||||||
|
this->y_low_ = this->height_;
|
||||||
|
this->x_high_ = 0;
|
||||||
|
this->y_high_ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t ILI9341Display::convert_to_16bit_color_(uint8_t color_8bit) {
|
||||||
|
int r = color_8bit >> 5;
|
||||||
|
int g = (color_8bit >> 2) & 0x07;
|
||||||
|
int b = color_8bit & 0x03;
|
||||||
|
uint16_t color = (r * 0x04) << 11;
|
||||||
|
color |= (g * 0x09) << 5;
|
||||||
|
color |= (b * 0x0A);
|
||||||
|
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t ILI9341Display::convert_to_8bit_color_(uint16_t color_16bit) {
|
||||||
|
// convert 16bit color to 8 bit buffer
|
||||||
|
uint8_t r = color_16bit >> 11;
|
||||||
|
uint8_t g = (color_16bit >> 5) & 0x3F;
|
||||||
|
uint8_t b = color_16bit & 0x1F;
|
||||||
|
|
||||||
|
return ((b / 0x0A) | ((g / 0x09) << 2) | ((r / 0x04) << 5));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ILI9341Display::fill(Color color) {
|
||||||
|
auto color565 = color.to_rgb_565();
|
||||||
|
memset(this->buffer_, convert_to_8bit_color_(color565), 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_(Color color) {
|
||||||
|
this->set_addr_window_(0, 0, this->get_width_internal(), this->get_height_internal());
|
||||||
|
this->start_data_();
|
||||||
|
|
||||||
|
auto color565 = color.to_rgb_565();
|
||||||
|
for (uint32_t i = 0; i < (this->get_width_internal()) * (this->get_height_internal()); i++) {
|
||||||
|
this->write_byte(color565 >> 8);
|
||||||
|
this->write_byte(color565);
|
||||||
|
buffer_[i] = 0;
|
||||||
|
}
|
||||||
|
this->end_data_();
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
// 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_;
|
||||||
|
|
||||||
|
uint32_t pos = (y * width_) + x;
|
||||||
|
auto color565 = color.to_rgb_565();
|
||||||
|
buffer_[pos] = convert_to_8bit_color_(color565);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 = pgm_read_byte(addr++)) > 0) {
|
||||||
|
x = pgm_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_; }
|
||||||
|
|
||||||
|
// M5Stack display
|
||||||
|
void ILI9341M5Stack::initialize() {
|
||||||
|
this->init_lcd_(INITCMD_M5STACK);
|
||||||
|
this->width_ = 320;
|
||||||
|
this->height_ = 240;
|
||||||
|
this->invert_display_(true);
|
||||||
|
this->fill_internal_(COLOR_BLACK);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 24_TFT display
|
||||||
|
void ILI9341TFT24::initialize() {
|
||||||
|
this->init_lcd_(INITCMD_TFT);
|
||||||
|
this->width_ = 240;
|
||||||
|
this->height_ = 320;
|
||||||
|
this->fill_internal_(COLOR_BLACK);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace ili9341
|
||||||
|
} // namespace esphome
|
92
esphome/components/ili9341/ili9341_display.h
Normal file
92
esphome/components/ili9341/ili9341_display.h
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
#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"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace ili9341 {
|
||||||
|
|
||||||
|
enum ILI9341Model {
|
||||||
|
M5STACK = 0,
|
||||||
|
TFT_24,
|
||||||
|
};
|
||||||
|
|
||||||
|
class ILI9341Display : 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> {
|
||||||
|
public:
|
||||||
|
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 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();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void draw_absolute_pixel_internal(int x, int y, Color color) override;
|
||||||
|
void setup_pins_();
|
||||||
|
|
||||||
|
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_(Color color);
|
||||||
|
void display_();
|
||||||
|
uint16_t convert_to_16bit_color_(uint8_t color_8bit);
|
||||||
|
uint8_t convert_to_8bit_color_(uint16_t color_16bit);
|
||||||
|
|
||||||
|
ILI9341Model model_;
|
||||||
|
int16_t width_{320}; ///< Display width as modified by current rotation
|
||||||
|
int16_t height_{240}; ///< 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};
|
||||||
|
|
||||||
|
uint32_t get_buffer_length_();
|
||||||
|
int get_width_internal() override;
|
||||||
|
int get_height_internal() override;
|
||||||
|
|
||||||
|
void start_command_();
|
||||||
|
void end_command_();
|
||||||
|
void start_data_();
|
||||||
|
void end_data_();
|
||||||
|
|
||||||
|
GPIOPin *reset_pin_{nullptr};
|
||||||
|
GPIOPin *led_pin_{nullptr};
|
||||||
|
GPIOPin *dc_pin_;
|
||||||
|
GPIOPin *busy_pin_{nullptr};
|
||||||
|
};
|
||||||
|
|
||||||
|
//----------- M5Stack display --------------
|
||||||
|
class ILI9341M5Stack : public ILI9341Display {
|
||||||
|
public:
|
||||||
|
void initialize() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
//----------- ILI9341_24_TFT display --------------
|
||||||
|
class ILI9341TFT24 : public ILI9341Display {
|
||||||
|
public:
|
||||||
|
void initialize() override;
|
||||||
|
};
|
||||||
|
} // namespace ili9341
|
||||||
|
} // namespace esphome
|
70
esphome/components/ili9341/ili9341_init.h
Normal file
70
esphome/components/ili9341/ili9341_init.h
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
#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
|
|
@ -55,6 +55,8 @@ enum SPIDataRate : uint32_t {
|
||||||
DATA_RATE_2MHZ = 2000000,
|
DATA_RATE_2MHZ = 2000000,
|
||||||
DATA_RATE_4MHZ = 4000000,
|
DATA_RATE_4MHZ = 4000000,
|
||||||
DATA_RATE_8MHZ = 8000000,
|
DATA_RATE_8MHZ = 8000000,
|
||||||
|
DATA_RATE_20MHZ = 20000000,
|
||||||
|
DATA_RATE_40MHZ = 40000000,
|
||||||
};
|
};
|
||||||
|
|
||||||
class SPIComponent : public Component {
|
class SPIComponent : public Component {
|
||||||
|
|
Loading…
Reference in a new issue