12constexpr static const char *
const TAG =
"display.mipi_spi";
15static constexpr uint8_t NORON = 0x13;
18static constexpr uint8_t ALL_ON = 0x23;
19static constexpr uint8_t WRAM = 0x24;
20static constexpr uint8_t MIPI = 0x26;
22static constexpr uint8_t RASET = 0x2B;
23static constexpr uint8_t CASET = 0x2A;
24static constexpr uint8_t WDATA = 0x2C;
25static constexpr uint8_t TEON = 0x35;
27static constexpr uint8_t PIXFMT = 0x3A;
28static constexpr uint8_t BRIGHTNESS = 0x51;
29static constexpr uint8_t SWIRE1 = 0x5A;
30static constexpr uint8_t SWIRE2 = 0x5B;
31static constexpr uint8_t PAGESEL = 0xFE;
36static constexpr uint8_t MADCTL_RGB = 0x00;
43static inline void put16_be(uint8_t *buf, uint16_t value) {
77 int WIDTH,
int HEIGHT,
int OFFSET_WIDTH,
int OFFSET_HEIGHT>
79 public spi::SPIDevice<spi::BIT_ORDER_MSB_FIRST, spi::CLOCK_POLARITY_LOW, spi::CLOCK_PHASE_LEADING,
80 spi::DATA_RATE_1MHZ> {
106 if (this->
dc_pin_ !=
nullptr) {
112 pin->digital_write(
true);
124 auto when =
millis() + 120;
128 while (index != vec.size()) {
129 if (vec.size() - index < 2) {
130 esph_log_e(TAG,
"Malformed init sequence");
134 uint8_t cmd = vec[index++];
135 uint8_t
x = vec[index++];
136 if (
x == DELAY_FLAG) {
137 esph_log_d(TAG,
"Delay %dms", cmd);
140 uint8_t num_args =
x & 0x7F;
141 if (vec.size() - index < num_args) {
142 esph_log_e(TAG,
"Malformed init sequence");
146 auto arg_byte = vec[index];
152 esph_log_d(TAG,
"Sleep %dms",
duration);
170 const auto *ptr = vec.data() + index;
171 esph_log_d(TAG,
"Command %02X, length %d, byte %02X", cmd, num_args, arg_byte);
174 if (cmd == SLEEP_OUT)
188 if (w <= 0 ||
h <= 0)
190 if (
get_pixel_mode(bitness) != BUFFERPIXEL || big_endian != IS_BIG_ENDIAN) {
192 esph_log_e(TAG,
"Unsupported color depth or bit order");
195 this->
write_to_display_(x_start, y_start, w,
h,
reinterpret_cast<const BUFFERTYPE *
>(ptr), x_offset, y_offset,
205 this->
model_, WIDTH, HEIGHT);
206 if constexpr (OFFSET_WIDTH != 0)
207 esph_log_config(TAG,
" Offset width: %u", OFFSET_WIDTH);
208 if constexpr (OFFSET_HEIGHT != 0)
209 esph_log_config(TAG,
" Offset height: %u", OFFSET_HEIGHT);
214 " Invert colors: %s\n"
216 " Display pixels: %d bits\n"
218 YESNO(this->
madctl_ & MADCTL_MV), YESNO(this->
madctl_ & (MADCTL_MX | MADCTL_XFLIP)),
220 this->
madctl_ & MADCTL_BGR ?
"BGR" :
"RGB", DISPLAYPIXEL * 8, IS_BIG_ENDIAN ?
"Big" :
"Little");
223 if (this->
cs_ !=
nullptr)
224 esph_log_config(TAG,
" CS Pin: %s", this->
cs_->
dump_summary().c_str());
231 " SPI Data rate: %dMHz\n"
232 " SPI Bus width: %d",
233 this->
mode_,
static_cast<unsigned>(this->
data_rate_ / 1000000), BUS_TYPE);
277 for (
size_t i = 0; i !=
len; i++) {
297 esph_log_v(TAG,
"Set addr %d/%d, %d/%d", x1, y1, x2, y2);
304 put16_be(buf + 2, y2);
307 put16_be(buf + 2, x2);
343 for (
size_t y = 0;
y !=
static_cast<size_t>(
h);
y++) {
362 void write_to_display_(
int x_start,
int y_start,
int w,
int h,
const BUFFERTYPE *ptr,
int x_offset,
int y_offset,
366 ptr += y_offset * (x_offset + w + x_pad) + x_offset;
367 if constexpr (BUFFERPIXEL == DISPLAYPIXEL) {
369 x_pad *
sizeof(BUFFERTYPE));
372 uint8_t dbuffer[DISPLAYPIXEL * 48];
373 uint8_t *dptr = dbuffer;
374 auto stride = x_offset + w + x_pad;
375 for (
size_t y = 0;
y !=
static_cast<size_t>(
h);
y++) {
376 for (
size_t x = 0;
x !=
static_cast<size_t>(w);
x++) {
377 auto color_val = ptr[
y * stride +
x];
380 if constexpr (IS_BIG_ENDIAN) {
381 *dptr++ = color_val & 0xF8;
382 *dptr++ = ((color_val & 0x7) << 5) | (color_val & 0xE000) >> 11;
383 *dptr++ = (color_val >> 5) & 0xF8;
385 *dptr++ = (color_val >> 8) & 0xF8;
386 *dptr++ = (color_val & 0x7E0) >> 3;
387 *dptr++ = color_val << 3;
391 *dptr++ = color_val << 6;
392 *dptr++ = (color_val & 0x1C) << 3;
393 *dptr++ = (color_val & 0xE0);
395 if constexpr (IS_BIG_ENDIAN) {
396 *dptr++ = (color_val & 0xE0) | ((color_val & 0x1C) >> 2);
397 *dptr++ = (color_val & 3) << 3;
399 *dptr++ = (color_val & 3) << 3;
400 *dptr++ = (color_val & 0xE0) | ((color_val & 0x1C) >> 2);
404 if (dptr == dbuffer +
sizeof(dbuffer)) {
411 if (dptr != dbuffer) {
450 int FRACTION,
unsigned ROUNDING>
451class MipiSpiBuffer :
public MipiSpi<BUFFERTYPE, BUFFERPIXEL, IS_BIG_ENDIAN, DISPLAYPIXEL, BUS_TYPE, WIDTH, HEIGHT,
452 OFFSET_WIDTH, OFFSET_HEIGHT> {
457 static constexpr unsigned BUFFER_WIDTH = (WIDTH + ROUNDING - 1) / ROUNDING * ROUNDING;
458 static constexpr unsigned BUFFER_HEIGHT = (HEIGHT + ROUNDING - 1) / ROUNDING * ROUNDING;
463 MipiSpi<BUFFERTYPE, BUFFERPIXEL, IS_BIG_ENDIAN, DISPLAYPIXEL, BUS_TYPE, WIDTH, HEIGHT, OFFSET_WIDTH,
467 " Buffer pixels: %d bits\n"
468 " Buffer fraction: 1/%d\n"
469 " Buffer bytes: %zu\n"
470 " Draw rounding: %u",
471 this->
rotation_, BUFFERPIXEL * 8, FRACTION,
476 MipiSpi<BUFFERTYPE, BUFFERPIXEL, IS_BIG_ENDIAN, DISPLAYPIXEL, BUS_TYPE, WIDTH, HEIGHT, OFFSET_WIDTH,
480 if (this->
buffer_ ==
nullptr) {
486#if ESPHOME_LOG_LEVEL == ESPHOME_LOG_LEVEL_VERBOSE
495#if ESPHOME_LOG_LEVEL == ESPHOME_LOG_LEVEL_VERBOSE
502 if (this->
page_ !=
nullptr) {
509#if ESPHOME_LOG_LEVEL == ESPHOME_LOG_LEVEL_VERBOSE
510 esph_log_v(TAG,
"Drawing from line %d took %dms", this->
start_line_,
millis() - lap);
515 esph_log_v(TAG,
"x_low %d, y_low %d, x_high %d, y_high %d", this->
x_low_, this->
y_low_, this->
x_high_,
520 this->
x_high_ = (this->
x_high_ + ROUNDING) / ROUNDING * ROUNDING - 1;
521 this->
y_high_ = (this->
y_high_ + ROUNDING) / ROUNDING * ROUNDING - 1;
525 this->y_low_ - this->
start_line_, BUFFER_WIDTH - w);
527 this->x_low_ = WIDTH;
528 this->y_low_ = HEIGHT;
531#if ESPHOME_LOG_LEVEL == ESPHOME_LOG_LEVEL_VERBOSE
532 esph_log_v(TAG,
"Write to display took %dms",
millis() - lap);
536#if ESPHOME_LOG_LEVEL == ESPHOME_LOG_LEVEL_VERBOSE
537 esph_log_v(TAG,
"Total update took %dms",
millis() - now);
604 return (color.
red & 0xE0) | (color.
g & 0xE0) >> 3 | color.
b >> 6;
606 if constexpr (IS_BIG_ENDIAN) {
607 return (color.
r & 0xF8) | color.
g >> 5 | (color.
g & 0x1C) << 11 | (color.
b & 0xF8) << 5;
609 return (color.
r & 0xF8) << 8 | (color.
g & 0xFC) << 3 | color.
b >> 3;
612 return static_cast<BUFFERTYPE
>(0);
virtual void mark_failed()
Mark this component as failed.
virtual std::string dump_summary() const =0
virtual void digital_write(bool value)=0
An STL allocator that uses SPI or internal RAM.
virtual void clear()
Clear the entire screen by filling it with OFF pixels.
Rect get_clipping() const
Get the current the clipping rectangle.
DisplayRotation rotation_
const display_writer_t & get_writer() const
Class for MIPI SPI displays with a buffer.
void draw_pixel_at(int x, int y, Color color) override
int get_height() override
static constexpr unsigned BUFFER_HEIGHT
static BUFFERTYPE convert_color(const Color &color)
static constexpr unsigned BUFFER_WIDTH
void dump_config() override
void fill(Color color) override
static void rotate_coordinates(int &x, int &y)
Base class for MIPI SPI displays.
std::vector< GPIOPin * > enable_pins_
void write_command_(uint8_t cmd, uint8_t data)
int get_height_internal() override
static PixelMode get_pixel_mode(display::ColorBitness bitness)
void set_addr_window_(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2)
int get_width_internal() override
void set_init_sequence(const std::vector< uint8_t > &sequence)
void set_reset_pin(GPIOPin *reset_pin)
void write_command_(uint8_t cmd)
void set_dc_pin(GPIOPin *dc_pin)
void set_invert_colors(bool invert_colors)
void set_brightness(uint8_t brightness)
void write_command_(uint8_t cmd, const uint8_t *bytes, size_t len)
void set_model(const char *model)
void write_display_data_(const uint8_t *ptr, size_t w, size_t h, size_t pad)
Writes a buffer to the display.
void dump_config() override
display::DisplayType get_display_type() override
void draw_pixels_at(int x_start, int y_start, int w, int h, const uint8_t *ptr, display::ColorOrder order, display::ColorBitness bitness, bool big_endian, int x_offset, int y_offset, int x_pad) override
void draw_pixel_at(int x, int y, Color color) override
void set_enable_pins(std::vector< GPIOPin * > enable_pins)
optional< uint8_t > brightness_
std::vector< uint8_t > init_sequence_
void write_to_display_(int x_start, int y_start, int w, int h, const BUFFERTYPE *ptr, int x_offset, int y_offset, int x_pad)
Writes a buffer to the display.
value_type const & value() const
The SPIDevice is what components using the SPI will create.
void spi_setup() override
void write_byte(uint8_t data)
void write_array(const uint8_t *data, size_t length)
void write_cmd_addr_data(size_t cmd_bits, uint32_t cmd, size_t addr_bits, uint32_t address, const uint8_t *data, size_t length, uint8_t bus_width=1)
@ DISPLAY_ROTATION_270_DEGREES
@ DISPLAY_ROTATION_180_DEGREES
@ DISPLAY_ROTATION_90_DEGREES
const uint8_t MADCTL_YFLIP
const uint8_t MADCTL_XFLIP
const uint8_t SW_RESET_CMD
Providing packet encoding functions for exchanging data with a remote host.
std::string format_hex_pretty(const uint8_t *data, size_t length, char separator, bool show_length)
Format a byte array in pretty-printed, human-readable hex format.
void IRAM_ATTR HOT delay(uint32_t ms)
uint32_t IRAM_ATTR HOT millis()