mirror of
https://github.com/esphome/esphome.git
synced 2024-12-25 06:54:52 +01:00
Add support for Pico-ResTouch-LCD-3.5 to ili9xxx driver (#6129)
* Working version of Waveshare 3.5 Res Touch driver. * Default color order BGR
This commit is contained in:
parent
4812997429
commit
23071e932a
4 changed files with 94 additions and 70 deletions
|
@ -66,6 +66,7 @@ MODELS = {
|
|||
"ST7789V": ili9xxx_ns.class_("ILI9XXXST7789V", ILI9XXXDisplay),
|
||||
"S3BOX": ili9xxx_ns.class_("ILI9XXXS3Box", ILI9XXXDisplay),
|
||||
"S3BOX_LITE": ili9xxx_ns.class_("ILI9XXXS3BoxLite", ILI9XXXDisplay),
|
||||
"WAVESHARE_RES_3_5": ili9xxx_ns.class_("WAVESHARERES35", ILI9XXXDisplay),
|
||||
}
|
||||
|
||||
COLOR_ORDERS = {
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
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
|
||||
|
||||
|
@ -17,13 +16,7 @@ static inline void put16_be(uint8_t *buf, uint16_t value) {
|
|||
buf[1] = value;
|
||||
}
|
||||
|
||||
void ILI9XXXDisplay::setup() {
|
||||
ESP_LOGD(TAG, "Setting up ILI9xxx");
|
||||
|
||||
this->setup_pins_();
|
||||
this->init_lcd_();
|
||||
|
||||
this->command(this->pre_invertcolors_ ? ILI9XXX_INVON : ILI9XXX_INVOFF);
|
||||
void ILI9XXXDisplay::set_madctl() {
|
||||
// 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_)
|
||||
|
@ -32,8 +25,19 @@ void ILI9XXXDisplay::setup() {
|
|||
mad |= MADCTL_MX;
|
||||
if (this->mirror_y_)
|
||||
mad |= MADCTL_MY;
|
||||
this->send_command(ILI9XXX_MADCTL, &mad, 1);
|
||||
this->command(ILI9XXX_MADCTL);
|
||||
this->data(mad);
|
||||
esph_log_d(TAG, "Wrote MADCTL 0x%02X", mad);
|
||||
}
|
||||
|
||||
void ILI9XXXDisplay::setup() {
|
||||
ESP_LOGD(TAG, "Setting up ILI9xxx");
|
||||
|
||||
this->setup_pins_();
|
||||
this->init_lcd_();
|
||||
|
||||
this->set_madctl();
|
||||
this->command(this->pre_invertcolors_ ? ILI9XXX_INVON : ILI9XXX_INVOFF);
|
||||
this->x_low_ = this->width_;
|
||||
this->y_low_ = this->height_;
|
||||
this->x_high_ = 0;
|
||||
|
@ -89,6 +93,7 @@ void ILI9XXXDisplay::dump_config() {
|
|||
LOG_PIN(" CS Pin: ", this->cs_);
|
||||
LOG_PIN(" DC Pin: ", this->dc_pin_);
|
||||
LOG_PIN(" Busy Pin: ", this->busy_pin_);
|
||||
ESP_LOGCONFIG(TAG, " Color order: %s", this->color_order_ == display::COLOR_ORDER_BGR ? "BGR" : "RGB");
|
||||
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_));
|
||||
|
@ -196,7 +201,6 @@ void ILI9XXXDisplay::display_() {
|
|||
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;
|
||||
}
|
||||
|
||||
|
@ -211,14 +215,13 @@ void ILI9XXXDisplay::display_() {
|
|||
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, "
|
||||
"height:%d, mode=%d, 18bit=%d, sw_time=%dus, mw_time=%dus)",
|
||||
"height:%zu, mode=%d, 18bit=%d, sw_time=%zuus, mw_time=%zuus)",
|
||||
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);
|
||||
ESP_LOGV(TAG, "Doing single write of %zu 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 {
|
||||
|
@ -267,7 +270,7 @@ void ILI9XXXDisplay::display_() {
|
|||
this->write_array(transfer_buffer, idx);
|
||||
}
|
||||
}
|
||||
this->disable();
|
||||
this->end_data_();
|
||||
ESP_LOGV(TAG, "Data write took %dms", (unsigned) (millis() - now));
|
||||
// invalidate watermarks
|
||||
this->x_low_ = this->width_;
|
||||
|
@ -290,7 +293,6 @@ void ILI9XXXDisplay::draw_pixels_at(int x_start, int y_start, int w, int h, cons
|
|||
return display::Display::draw_pixels_at(x_start, y_start, w, h, ptr, order, bitness, big_endian, x_offset, y_offset,
|
||||
x_pad);
|
||||
}
|
||||
this->enable();
|
||||
this->set_addr_window_(x_start, y_start, x_start + w - 1, y_start + h - 1);
|
||||
// x_ and y_offset are offsets into the source buffer, unrelated to our own offsets into the display.
|
||||
if (x_offset == 0 && x_pad == 0 && y_offset == 0) {
|
||||
|
@ -302,7 +304,7 @@ void ILI9XXXDisplay::draw_pixels_at(int x_start, int y_start, int w, int h, cons
|
|||
this->write_array(ptr + (y + y_offset) * stride + x_offset, w * 2);
|
||||
}
|
||||
}
|
||||
this->disable();
|
||||
this->end_data_();
|
||||
}
|
||||
|
||||
// should return the total size: return this->get_width_internal() * this->get_height_internal() * 2 // 16bit color
|
||||
|
@ -328,20 +330,6 @@ void ILI9XXXDisplay::send_command(uint8_t command_byte, const uint8_t *data_byte
|
|||
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();
|
||||
|
@ -357,9 +345,9 @@ void ILI9XXXDisplay::end_data_() { this->disable(); }
|
|||
void ILI9XXXDisplay::reset_() {
|
||||
if (this->reset_pin_ != nullptr) {
|
||||
this->reset_pin_->digital_write(false);
|
||||
delay(10);
|
||||
delay(20);
|
||||
this->reset_pin_->digital_write(true);
|
||||
delay(10);
|
||||
delay(20);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -369,7 +357,7 @@ void ILI9XXXDisplay::init_lcd_() {
|
|||
while ((cmd = *addr++) > 0) {
|
||||
x = *addr++;
|
||||
num_args = x & 0x7F;
|
||||
send_command(cmd, addr, num_args);
|
||||
this->send_command(cmd, addr, num_args);
|
||||
addr += num_args;
|
||||
if (x & 0x80)
|
||||
delay(150); // NOLINT
|
||||
|
@ -377,24 +365,19 @@ void ILI9XXXDisplay::init_lcd_() {
|
|||
}
|
||||
|
||||
// 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);
|
||||
this->command(ILI9XXX_CASET);
|
||||
this->data(x1 >> 8);
|
||||
this->data(x1 & 0xFF);
|
||||
this->data(x2 >> 8);
|
||||
this->data(x2 & 0xFF);
|
||||
this->command(ILI9XXX_PASET); // Page address set
|
||||
this->data(y1 >> 8);
|
||||
this->data(y1 & 0xFF);
|
||||
this->data(y2 >> 8);
|
||||
this->data(y2 & 0xFF);
|
||||
this->command(ILI9XXX_RAMWR); // Write to RAM
|
||||
this->start_data_();
|
||||
}
|
||||
|
||||
void ILI9XXXDisplay::invert_colors(bool invert) {
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
namespace esphome {
|
||||
namespace ili9xxx {
|
||||
|
||||
static const char *const TAG = "ili9xxx";
|
||||
const size_t ILI9XXX_TRANSFER_BUFFER_SIZE = 126; // ensure this is divisible by 6
|
||||
|
||||
enum ILI9XXXColorMode {
|
||||
|
@ -32,6 +33,7 @@ class ILI9XXXDisplay : public display::DisplayBuffer,
|
|||
while ((cmd = *addr++) != 0) {
|
||||
num_args = *addr++ & 0x7F;
|
||||
bits = *addr;
|
||||
esph_log_d(TAG, "Command %02X, length %d, bits %02X", cmd, num_args, bits);
|
||||
switch (cmd) {
|
||||
case ILI9XXX_MADCTL: {
|
||||
this->swap_xy_ = (bits & MADCTL_MV) != 0;
|
||||
|
@ -68,10 +70,9 @@ class ILI9XXXDisplay : public display::DisplayBuffer,
|
|||
this->offset_y_ = offset_y;
|
||||
}
|
||||
void invert_colors(bool invert);
|
||||
void command(uint8_t value);
|
||||
void data(uint8_t value);
|
||||
virtual void command(uint8_t value);
|
||||
virtual 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; }
|
||||
|
@ -92,6 +93,7 @@ class ILI9XXXDisplay : public display::DisplayBuffer,
|
|||
void draw_absolute_pixel_internal(int x, int y, Color color) override;
|
||||
void setup_pins_();
|
||||
|
||||
virtual void set_madctl();
|
||||
void display_();
|
||||
void init_lcd_();
|
||||
void set_addr_window_(uint16_t x, uint16_t y, uint16_t x2, uint16_t y2);
|
||||
|
@ -127,7 +129,7 @@ class ILI9XXXDisplay : public display::DisplayBuffer,
|
|||
bool need_update_ = false;
|
||||
bool is_18bitdisplay_ = false;
|
||||
bool pre_invertcolors_ = false;
|
||||
display::ColorOrder color_order_{};
|
||||
display::ColorOrder color_order_{display::COLOR_ORDER_BGR};
|
||||
bool swap_xy_{};
|
||||
bool mirror_x_{};
|
||||
bool mirror_y_{};
|
||||
|
@ -181,10 +183,48 @@ class ILI9XXXILI9486 : public ILI9XXXDisplay {
|
|||
ILI9XXXILI9486() : ILI9XXXDisplay(INITCMD_ILI9486, 480, 320, false) {}
|
||||
};
|
||||
|
||||
//----------- ILI9XXX_35_TFT rotated display --------------
|
||||
class ILI9XXXILI9488 : public ILI9XXXDisplay {
|
||||
public:
|
||||
ILI9XXXILI9488() : ILI9XXXDisplay(INITCMD_ILI9488, 480, 320, true) {}
|
||||
ILI9XXXILI9488(const uint8_t *seq = INITCMD_ILI9488) : ILI9XXXDisplay(seq, 480, 320, true) {}
|
||||
|
||||
protected:
|
||||
void set_madctl() override {
|
||||
uint8_t mad = this->color_order_ == display::COLOR_ORDER_BGR ? MADCTL_BGR : MADCTL_RGB;
|
||||
uint8_t dfun = 0x22;
|
||||
this->width_ = 320;
|
||||
this->height_ = 480;
|
||||
if (!(this->swap_xy_ || this->mirror_x_ || this->mirror_y_)) {
|
||||
// no transforms
|
||||
} else if (this->mirror_y_ && this->mirror_x_) {
|
||||
// rotate 180
|
||||
dfun = 0x42;
|
||||
} else if (this->swap_xy_) {
|
||||
this->width_ = 480;
|
||||
this->height_ = 320;
|
||||
mad |= 0x20;
|
||||
if (this->mirror_x_) {
|
||||
dfun = 0x02;
|
||||
} else {
|
||||
dfun = 0x62;
|
||||
}
|
||||
}
|
||||
this->command(ILI9XXX_DFUNCTR);
|
||||
this->data(0);
|
||||
this->data(dfun);
|
||||
this->command(ILI9XXX_MADCTL);
|
||||
this->data(mad);
|
||||
}
|
||||
};
|
||||
//----------- Waveshare 3.5 Res Touch - ILI9488 interfaced via 16 bit shift register to parallel */
|
||||
class WAVESHARERES35 : public ILI9XXXILI9488 {
|
||||
public:
|
||||
WAVESHARERES35() : ILI9XXXILI9488(INITCMD_WAVESHARE_RES_3_5) {}
|
||||
void data(uint8_t value) override {
|
||||
this->start_data_();
|
||||
this->write_byte(0);
|
||||
this->write_byte(value);
|
||||
this->end_data_();
|
||||
}
|
||||
};
|
||||
|
||||
//----------- ILI9XXX_35_TFT origin colors rotated display --------------
|
||||
|
|
|
@ -141,7 +141,8 @@ static const uint8_t PROGMEM INITCMD_ILI9486[] = {
|
|||
0x00 // End of list
|
||||
};
|
||||
|
||||
static const uint8_t PROGMEM INITCMD_ILI9488[] = {
|
||||
|
||||
static const uint8_t INITCMD_ILI9488[] = {
|
||||
ILI9XXX_GMCTRP1,15, 0x0f, 0x24, 0x1c, 0x0a, 0x0f, 0x08, 0x43, 0x88, 0x32, 0x0f, 0x10, 0x06, 0x0f, 0x07, 0x00,
|
||||
ILI9XXX_GMCTRN1,15, 0x0F, 0x38, 0x30, 0x09, 0x0f, 0x0f, 0x4e, 0x77, 0x3c, 0x07, 0x10, 0x05, 0x23, 0x1b, 0x00,
|
||||
|
||||
|
@ -153,28 +154,27 @@ static const uint8_t PROGMEM INITCMD_ILI9488[] = {
|
|||
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 INITCMD_WAVESHARE_RES_3_5[] = {
|
||||
ILI9XXX_PWCTR3, 1, 0x33,
|
||||
ILI9XXX_VMCTR1, 3, 0x00, 0x1e, 0x80,
|
||||
ILI9XXX_FRMCTR1, 1, 0xA0,
|
||||
ILI9XXX_GMCTRP1, 15, 0x0, 0x13, 0x18, 0x04, 0x0F, 0x06, 0x3a, 0x56, 0x4d, 0x03, 0x0a, 0x06, 0x30, 0x3e, 0x0f,
|
||||
ILI9XXX_GMCTRN1, 15, 0x0, 0x13, 0x18, 0x01, 0x11, 0x06, 0x38, 0x34, 0x4d, 0x06, 0x0d, 0x0b, 0x31, 0x37, 0x0f,
|
||||
ILI9XXX_PIXFMT, 1, 0x55,
|
||||
ILI9XXX_SLPOUT, 0x80, // slpout, delay
|
||||
ILI9XXX_DISPON, 0,
|
||||
0x00 // End of list
|
||||
};
|
||||
|
||||
static const uint8_t PROGMEM INITCMD_ILI9488_A[] = {
|
||||
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,
|
||||
|
|
Loading…
Reference in a new issue