ESPHome 2026.2.1
Loading...
Searching...
No Matches
mipi_spi.h
Go to the documentation of this file.
1#pragma once
2
3#include <utility>
4
9
10namespace esphome {
11namespace mipi_spi {
12
13constexpr static const char *const TAG = "display.mipi_spi";
14
15// Maximum bytes to log for commands (truncated if larger)
16static constexpr size_t MIPI_SPI_MAX_CMD_LOG_BYTES = 64;
17static constexpr uint8_t SW_RESET_CMD = 0x01;
18static constexpr uint8_t SLEEP_OUT = 0x11;
19static constexpr uint8_t NORON = 0x13;
20static constexpr uint8_t INVERT_OFF = 0x20;
21static constexpr uint8_t INVERT_ON = 0x21;
22static constexpr uint8_t ALL_ON = 0x23;
23static constexpr uint8_t WRAM = 0x24;
24static constexpr uint8_t MIPI = 0x26;
25static constexpr uint8_t DISPLAY_ON = 0x29;
26static constexpr uint8_t RASET = 0x2B;
27static constexpr uint8_t CASET = 0x2A;
28static constexpr uint8_t WDATA = 0x2C;
29static constexpr uint8_t TEON = 0x35;
30static constexpr uint8_t MADCTL_CMD = 0x36;
31static constexpr uint8_t PIXFMT = 0x3A;
32static constexpr uint8_t BRIGHTNESS = 0x51;
33static constexpr uint8_t SWIRE1 = 0x5A;
34static constexpr uint8_t SWIRE2 = 0x5B;
35static constexpr uint8_t PAGESEL = 0xFE;
36
37static constexpr uint8_t MADCTL_MY = 0x80; // Bit 7 Bottom to top
38static constexpr uint8_t MADCTL_MX = 0x40; // Bit 6 Right to left
39static constexpr uint8_t MADCTL_MV = 0x20; // Bit 5 Swap axes
40static constexpr uint8_t MADCTL_RGB = 0x00; // Bit 3 Red-Green-Blue pixel order
41static constexpr uint8_t MADCTL_BGR = 0x08; // Bit 3 Blue-Green-Red pixel order
42static constexpr uint8_t MADCTL_XFLIP = 0x02; // Mirror the display horizontally
43static constexpr uint8_t MADCTL_YFLIP = 0x01; // Mirror the display vertically
44
45static constexpr uint8_t DELAY_FLAG = 0xFF;
46// store a 16 bit value in a buffer, big endian.
47static inline void put16_be(uint8_t *buf, uint16_t value) {
48 buf[0] = value >> 8;
49 buf[1] = value;
50}
51
52// Buffer mode, conveniently also the number of bytes in a pixel
58
59enum BusType {
63 BUS_TYPE_SINGLE_16 = 16, // Single bit bus, but 16 bits per transfer
64};
65
66// Helper function for dump_config - defined in mipi_spi.cpp to allow use of LOG_PIN macro
67void internal_dump_config(const char *model, int width, int height, int offset_width, int offset_height, uint8_t madctl,
68 bool invert_colors, int display_bits, bool is_big_endian, const optional<uint8_t> &brightness,
69 GPIOPin *cs, GPIOPin *reset, GPIOPin *dc, int spi_mode, uint32_t data_rate, int bus_width);
70
85template<typename BUFFERTYPE, PixelMode BUFFERPIXEL, bool IS_BIG_ENDIAN, PixelMode DISPLAYPIXEL, BusType BUS_TYPE,
86 int WIDTH, int HEIGHT, int OFFSET_WIDTH, int OFFSET_HEIGHT>
88 public spi::SPIDevice<spi::BIT_ORDER_MSB_FIRST, spi::CLOCK_POLARITY_LOW, spi::CLOCK_PHASE_LEADING,
89 spi::DATA_RATE_1MHZ> {
90 public:
91 MipiSpi() = default;
92 void update() override { this->stop_poller(); }
93 void draw_pixel_at(int x, int y, Color color) override {}
94 void set_model(const char *model) { this->model_ = model; }
95 void set_reset_pin(GPIOPin *reset_pin) { this->reset_pin_ = reset_pin; }
96 void set_enable_pins(std::vector<GPIOPin *> enable_pins) { this->enable_pins_ = std::move(enable_pins); }
97 void set_dc_pin(GPIOPin *dc_pin) { this->dc_pin_ = dc_pin; }
98 void set_invert_colors(bool invert_colors) {
99 this->invert_colors_ = invert_colors;
100 this->reset_params_();
101 }
102 void set_brightness(uint8_t brightness) {
103 this->brightness_ = brightness;
104 this->reset_params_();
105 }
107
108 int get_width_internal() override { return WIDTH; }
109 int get_height_internal() override { return HEIGHT; }
110 void set_init_sequence(const std::vector<uint8_t> &sequence) { this->init_sequence_ = sequence; }
111
112 // reset the display, and write the init sequence
113 void setup() override {
114 this->spi_setup();
115 if (this->dc_pin_ != nullptr) {
116 this->dc_pin_->setup();
117 this->dc_pin_->digital_write(false);
118 }
119 for (auto *pin : this->enable_pins_) {
120 pin->setup();
121 pin->digital_write(true);
122 }
123 if (this->reset_pin_ != nullptr) {
124 this->reset_pin_->setup();
125 this->reset_pin_->digital_write(true);
126 delay(5);
127 this->reset_pin_->digital_write(false);
128 delay(5);
129 this->reset_pin_->digital_write(true);
130 }
131
132 // need to know when the display is ready for SLPOUT command - will be 120ms after reset
133 auto when = millis() + 120;
134 delay(10);
135 size_t index = 0;
136 auto &vec = this->init_sequence_;
137 while (index != vec.size()) {
138 if (vec.size() - index < 2) {
139 esph_log_e(TAG, "Malformed init sequence");
140 this->mark_failed();
141 return;
142 }
143 uint8_t cmd = vec[index++];
144 uint8_t x = vec[index++];
145 if (x == DELAY_FLAG) {
146 esph_log_d(TAG, "Delay %dms", cmd);
147 delay(cmd);
148 } else {
149 uint8_t num_args = x & 0x7F;
150 if (vec.size() - index < num_args) {
151 esph_log_e(TAG, "Malformed init sequence");
152 this->mark_failed();
153 return;
154 }
155 auto arg_byte = vec[index];
156 switch (cmd) {
157 case SLEEP_OUT: {
158 // are we ready, boots?
159 int duration = when - millis();
160 if (duration > 0) {
161 esph_log_d(TAG, "Sleep %dms", duration);
163 }
164 } break;
165
166 case INVERT_ON:
167 this->invert_colors_ = true;
168 break;
169 case MADCTL_CMD:
170 this->madctl_ = arg_byte;
171 break;
172 case BRIGHTNESS:
173 this->brightness_ = arg_byte;
174 break;
175
176 default:
177 break;
178 }
179 const auto *ptr = vec.data() + index;
180 esph_log_d(TAG, "Command %02X, length %d, byte %02X", cmd, num_args, arg_byte);
181 this->write_command_(cmd, ptr, num_args);
182 index += num_args;
183 if (cmd == SLEEP_OUT)
184 delay(10);
185 }
186 }
187 // init sequence no longer needed
188 this->init_sequence_.clear();
189 }
190
191 // Drawing operations
192
193 void draw_pixels_at(int x_start, int y_start, int w, int h, const uint8_t *ptr, display::ColorOrder order,
194 display::ColorBitness bitness, bool big_endian, int x_offset, int y_offset, int x_pad) override {
195 if (this->is_failed())
196 return;
197 if (w <= 0 || h <= 0)
198 return;
199 if (get_pixel_mode(bitness) != BUFFERPIXEL || big_endian != IS_BIG_ENDIAN) {
200 // note that the usual logging macros are banned in header files, so use their replacement
201 esph_log_e(TAG, "Unsupported color depth or bit order");
202 return;
203 }
204 this->write_to_display_(x_start, y_start, w, h, reinterpret_cast<const BUFFERTYPE *>(ptr), x_offset, y_offset,
205 x_pad);
206 }
207
208 void dump_config() override {
209 internal_dump_config(this->model_, WIDTH, HEIGHT, OFFSET_WIDTH, OFFSET_HEIGHT, this->madctl_, this->invert_colors_,
210 DISPLAYPIXEL * 8, IS_BIG_ENDIAN, this->brightness_, this->cs_, this->reset_pin_, this->dc_pin_,
211 this->mode_, this->data_rate_, BUS_TYPE);
212 }
213
214 protected:
215 /* METHODS */
216 // convenience functions to write commands with or without data
217 void write_command_(uint8_t cmd, uint8_t data) { this->write_command_(cmd, &data, 1); }
218 void write_command_(uint8_t cmd) { this->write_command_(cmd, &cmd, 0); }
219
220 // Writes a command to the display, with the given bytes.
221 void write_command_(uint8_t cmd, const uint8_t *bytes, size_t len) {
222#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE
223 char hex_buf[format_hex_pretty_size(MIPI_SPI_MAX_CMD_LOG_BYTES)];
224 esph_log_v(TAG, "Command %02X, length %d, bytes %s", cmd, len, format_hex_pretty_to(hex_buf, bytes, len));
225#endif
226 if constexpr (BUS_TYPE == BUS_TYPE_QUAD) {
227 this->enable();
228 this->write_cmd_addr_data(8, 0x02, 24, cmd << 8, bytes, len);
229 this->disable();
230 } else if constexpr (BUS_TYPE == BUS_TYPE_OCTAL) {
231 this->dc_pin_->digital_write(false);
232 this->enable();
233 this->write_cmd_addr_data(0, 0, 0, 0, &cmd, 1, 8);
234 this->disable();
235 this->dc_pin_->digital_write(true);
236 if (len != 0) {
237 this->enable();
238 this->write_cmd_addr_data(0, 0, 0, 0, bytes, len, 8);
239 this->disable();
240 }
241 } else if constexpr (BUS_TYPE == BUS_TYPE_SINGLE) {
242 this->dc_pin_->digital_write(false);
243 this->enable();
244 this->write_byte(cmd);
245 this->disable();
246 this->dc_pin_->digital_write(true);
247 if (len != 0) {
248 this->enable();
249 this->write_array(bytes, len);
250 this->disable();
251 }
252 } else if constexpr (BUS_TYPE == BUS_TYPE_SINGLE_16) {
253 this->dc_pin_->digital_write(false);
254 this->enable();
255 this->write_byte(cmd);
256 this->disable();
257 this->dc_pin_->digital_write(true);
258 for (size_t i = 0; i != len; i++) {
259 this->enable();
260 this->write_byte(0);
261 this->write_byte(bytes[i]);
262 this->disable();
263 }
264 }
265 }
266
267 // write changed parameters to the display
269 if (!this->is_ready())
270 return;
271 this->write_command_(this->invert_colors_ ? INVERT_ON : INVERT_OFF);
272 if (this->brightness_.has_value())
273 this->write_command_(BRIGHTNESS, this->brightness_.value());
274 }
275
276 // set the address window for the next data write
277 void set_addr_window_(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2) {
278 esph_log_v(TAG, "Set addr %d/%d, %d/%d", x1, y1, x2, y2);
279 uint8_t buf[4];
280 x1 += OFFSET_WIDTH;
281 x2 += OFFSET_WIDTH;
282 y1 += OFFSET_HEIGHT;
283 y2 += OFFSET_HEIGHT;
284 put16_be(buf, y1);
285 put16_be(buf + 2, y2);
286 this->write_command_(RASET, buf, sizeof buf);
287 put16_be(buf, x1);
288 put16_be(buf + 2, x2);
289 this->write_command_(CASET, buf, sizeof buf);
290 if constexpr (BUS_TYPE != BUS_TYPE_QUAD) {
291 this->write_command_(WDATA);
292 }
293 }
294
295 // map the display color bitness to the pixel mode
297 switch (bitness) {
299 return PIXEL_MODE_18; // 18 bits per pixel
301 return PIXEL_MODE_16; // 16 bits per pixel
302 default:
303 return PIXEL_MODE_8; // Default to 8 bits per pixel
304 }
305 }
306
314 void write_display_data_(const uint8_t *ptr, size_t w, size_t h, size_t pad) {
315 if (pad == 0) {
316 if constexpr (BUS_TYPE == BUS_TYPE_SINGLE || BUS_TYPE == BUS_TYPE_SINGLE_16) {
317 this->write_array(ptr, w * h);
318 } else if constexpr (BUS_TYPE == BUS_TYPE_QUAD) {
319 this->write_cmd_addr_data(8, 0x32, 24, WDATA << 8, ptr, w * h, 4);
320 } else if constexpr (BUS_TYPE == BUS_TYPE_OCTAL) {
321 this->write_cmd_addr_data(0, 0, 0, 0, ptr, w * h, 8);
322 }
323 } else {
324 for (size_t y = 0; y != static_cast<size_t>(h); y++) {
325 if constexpr (BUS_TYPE == BUS_TYPE_SINGLE || BUS_TYPE == BUS_TYPE_SINGLE_16) {
326 this->write_array(ptr, w);
327 } else if constexpr (BUS_TYPE == BUS_TYPE_QUAD) {
328 this->write_cmd_addr_data(8, 0x32, 24, WDATA << 8, ptr, w, 4);
329 } else if constexpr (BUS_TYPE == BUS_TYPE_OCTAL) {
330 this->write_cmd_addr_data(0, 0, 0, 0, ptr, w, 8);
331 }
332 ptr += w + pad;
333 }
334 }
335 }
336
343 void write_to_display_(int x_start, int y_start, int w, int h, const BUFFERTYPE *ptr, int x_offset, int y_offset,
344 int x_pad) {
345 this->set_addr_window_(x_start, y_start, x_start + w - 1, y_start + h - 1);
346 this->enable();
347 ptr += y_offset * (x_offset + w + x_pad) + x_offset;
348 if constexpr (BUFFERPIXEL == DISPLAYPIXEL) {
349 this->write_display_data_(reinterpret_cast<const uint8_t *>(ptr), w * sizeof(BUFFERTYPE), h,
350 x_pad * sizeof(BUFFERTYPE));
351 } else {
352 // type conversion required, do it in chunks
353 uint8_t dbuffer[DISPLAYPIXEL * 48];
354 uint8_t *dptr = dbuffer;
355 auto stride = x_offset + w + x_pad; // stride in pixels
356 for (size_t y = 0; y != static_cast<size_t>(h); y++) {
357 for (size_t x = 0; x != static_cast<size_t>(w); x++) {
358 auto color_val = ptr[y * stride + x];
359 if constexpr (DISPLAYPIXEL == PIXEL_MODE_18 && BUFFERPIXEL == PIXEL_MODE_16) {
360 // 16 to 18 bit conversion
361 if constexpr (IS_BIG_ENDIAN) {
362 *dptr++ = color_val & 0xF8;
363 *dptr++ = ((color_val & 0x7) << 5) | (color_val & 0xE000) >> 11;
364 *dptr++ = (color_val >> 5) & 0xF8;
365 } else {
366 *dptr++ = (color_val >> 8) & 0xF8; // Blue
367 *dptr++ = (color_val & 0x7E0) >> 3;
368 *dptr++ = color_val << 3;
369 }
370 } else if constexpr (DISPLAYPIXEL == PIXEL_MODE_18 && BUFFERPIXEL == PIXEL_MODE_8) {
371 // 8 bit to 18 bit conversion
372 *dptr++ = color_val << 6; // Blue
373 *dptr++ = (color_val & 0x1C) << 3; // Green
374 *dptr++ = (color_val & 0xE0); // Red
375 } else if constexpr (DISPLAYPIXEL == PIXEL_MODE_16 && BUFFERPIXEL == PIXEL_MODE_8) {
376 if constexpr (IS_BIG_ENDIAN) {
377 *dptr++ = (color_val & 0xE0) | ((color_val & 0x1C) >> 2);
378 *dptr++ = (color_val & 3) << 3;
379 } else {
380 *dptr++ = (color_val & 3) << 3;
381 *dptr++ = (color_val & 0xE0) | ((color_val & 0x1C) >> 2);
382 }
383 }
384 // buffer full? Flush.
385 if (dptr == dbuffer + sizeof(dbuffer)) {
386 this->write_display_data_(dbuffer, sizeof(dbuffer), 1, 0);
387 dptr = dbuffer;
388 }
389 }
390 }
391 // flush any remaining data
392 if (dptr != dbuffer) {
393 this->write_display_data_(dbuffer, dptr - dbuffer, 1, 0);
394 }
395 }
396 this->disable();
397 }
398
399 /* PROPERTIES */
400
401 // GPIO pins
403 std::vector<GPIOPin *> enable_pins_{};
404 GPIOPin *dc_pin_{nullptr};
405
406 // other properties set by configuration
409 const char *model_{"Unknown"};
410 std::vector<uint8_t> init_sequence_{};
411 uint8_t madctl_{};
412};
413
429template<typename BUFFERTYPE, PixelMode BUFFERPIXEL, bool IS_BIG_ENDIAN, PixelMode DISPLAYPIXEL, BusType BUS_TYPE,
430 uint16_t WIDTH, uint16_t HEIGHT, int OFFSET_WIDTH, int OFFSET_HEIGHT, display::DisplayRotation ROTATION,
431 int FRACTION, unsigned ROUNDING>
432class MipiSpiBuffer : public MipiSpi<BUFFERTYPE, BUFFERPIXEL, IS_BIG_ENDIAN, DISPLAYPIXEL, BUS_TYPE, WIDTH, HEIGHT,
433 OFFSET_WIDTH, OFFSET_HEIGHT> {
434 public:
435 // these values define the buffer size needed to write in accordance with the chip pixel alignment
436 // requirements. If the required rounding does not divide the width and height, we round up to the next multiple and
437 // ignore the extra columns and rows when drawing, but use them to write to the display.
438 static constexpr unsigned BUFFER_WIDTH = (WIDTH + ROUNDING - 1) / ROUNDING * ROUNDING;
439 static constexpr unsigned BUFFER_HEIGHT = (HEIGHT + ROUNDING - 1) / ROUNDING * ROUNDING;
440
441 MipiSpiBuffer() { this->rotation_ = ROTATION; }
442
443 void dump_config() override {
444 MipiSpi<BUFFERTYPE, BUFFERPIXEL, IS_BIG_ENDIAN, DISPLAYPIXEL, BUS_TYPE, WIDTH, HEIGHT, OFFSET_WIDTH,
445 OFFSET_HEIGHT>::dump_config();
446 esph_log_config(TAG,
447 " Rotation: %d°\n"
448 " Buffer pixels: %d bits\n"
449 " Buffer fraction: 1/%d\n"
450 " Buffer bytes: %zu\n"
451 " Draw rounding: %u",
452 this->rotation_, BUFFERPIXEL * 8, FRACTION,
453 sizeof(BUFFERTYPE) * BUFFER_WIDTH * BUFFER_HEIGHT / FRACTION, ROUNDING);
454 }
455
456 void setup() override {
457 MipiSpi<BUFFERTYPE, BUFFERPIXEL, IS_BIG_ENDIAN, DISPLAYPIXEL, BUS_TYPE, WIDTH, HEIGHT, OFFSET_WIDTH,
458 OFFSET_HEIGHT>::setup();
459 RAMAllocator<BUFFERTYPE> allocator{};
460 this->buffer_ = allocator.allocate(BUFFER_WIDTH * BUFFER_HEIGHT / FRACTION);
461 if (this->buffer_ == nullptr) {
462 this->mark_failed(LOG_STR("Buffer allocation failed"));
463 }
464 }
465
466 void update() override {
467#if ESPHOME_LOG_LEVEL == ESPHOME_LOG_LEVEL_VERBOSE
468 auto now = millis();
469#endif
470 if (this->is_failed()) {
471 return;
472 }
473 // for updates with a small buffer, we repeatedly call the writer_ function, clipping the height to a fraction of
474 // the display height,
475 for (this->start_line_ = 0; this->start_line_ < HEIGHT; this->start_line_ += HEIGHT / FRACTION) {
476#if ESPHOME_LOG_LEVEL == ESPHOME_LOG_LEVEL_VERBOSE
477 auto lap = millis();
478#endif
479 this->end_line_ = this->start_line_ + HEIGHT / FRACTION;
480 if (this->auto_clear_enabled_) {
481 this->clear();
482 }
483 if (this->page_ != nullptr) {
484 this->page_->get_writer()(*this);
485 } else if (this->writer_.has_value()) {
486 (*this->writer_)(*this);
487 } else {
488 this->test_card();
489 }
490#if ESPHOME_LOG_LEVEL == ESPHOME_LOG_LEVEL_VERBOSE
491 esph_log_v(TAG, "Drawing from line %d took %dms", this->start_line_, millis() - lap);
492 lap = millis();
493#endif
494 if (this->x_low_ > this->x_high_ || this->y_low_ > this->y_high_)
495 return;
496 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_,
497 this->y_high_);
498 // Some chips require that the drawing window be aligned on certain boundaries
499 this->x_low_ = this->x_low_ / ROUNDING * ROUNDING;
500 this->y_low_ = this->y_low_ / ROUNDING * ROUNDING;
501 this->x_high_ = (this->x_high_ + ROUNDING) / ROUNDING * ROUNDING - 1;
502 this->y_high_ = (this->y_high_ + ROUNDING) / ROUNDING * ROUNDING - 1;
503 int w = this->x_high_ - this->x_low_ + 1;
504 int h = this->y_high_ - this->y_low_ + 1;
505 this->write_to_display_(this->x_low_, this->y_low_, w, h, this->buffer_, this->x_low_,
506 this->y_low_ - this->start_line_, BUFFER_WIDTH - w);
507 // invalidate watermarks
508 this->x_low_ = WIDTH;
509 this->y_low_ = HEIGHT;
510 this->x_high_ = 0;
511 this->y_high_ = 0;
512#if ESPHOME_LOG_LEVEL == ESPHOME_LOG_LEVEL_VERBOSE
513 esph_log_v(TAG, "Write to display took %dms", millis() - lap);
514 lap = millis();
515#endif
516 }
517#if ESPHOME_LOG_LEVEL == ESPHOME_LOG_LEVEL_VERBOSE
518 esph_log_v(TAG, "Total update took %dms", millis() - now);
519#endif
520 }
521
522 // Draw a pixel at the given coordinates.
523 void draw_pixel_at(int x, int y, Color color) override {
524 if (!this->get_clipping().inside(x, y))
525 return;
527 if (x < 0 || x >= WIDTH || y < this->start_line_ || y >= this->end_line_)
528 return;
529 this->buffer_[(y - this->start_line_) * BUFFER_WIDTH + x] = convert_color(color);
530 if (x < this->x_low_) {
531 this->x_low_ = x;
532 }
533 if (x > this->x_high_) {
534 this->x_high_ = x;
535 }
536 if (y < this->y_low_) {
537 this->y_low_ = y;
538 }
539 if (y > this->y_high_) {
540 this->y_high_ = y;
541 }
542 }
543
544 // Fills the display with a color.
545 void fill(Color color) override {
546 // If clipping is active, fall back to base implementation
547 if (this->get_clipping().is_set()) {
549 return;
550 }
551
552 this->x_low_ = 0;
553 this->y_low_ = this->start_line_;
554 this->x_high_ = WIDTH - 1;
555 this->y_high_ = this->end_line_ - 1;
556 std::fill_n(this->buffer_, HEIGHT * BUFFER_WIDTH / FRACTION, convert_color(color));
557 }
558
559 int get_width() override {
561 return HEIGHT;
562 return WIDTH;
563 }
564
565 int get_height() override {
567 return WIDTH;
568 return HEIGHT;
569 }
570
571 protected:
572 // Rotate the coordinates to match the display orientation.
573 static void rotate_coordinates(int &x, int &y) {
574 if constexpr (ROTATION == display::DISPLAY_ROTATION_180_DEGREES) {
575 x = WIDTH - x - 1;
576 y = HEIGHT - y - 1;
577 } else if constexpr (ROTATION == display::DISPLAY_ROTATION_90_DEGREES) {
578 auto tmp = x;
579 x = WIDTH - y - 1;
580 y = tmp;
581 } else if constexpr (ROTATION == display::DISPLAY_ROTATION_270_DEGREES) {
582 auto tmp = y;
583 y = HEIGHT - x - 1;
584 x = tmp;
585 }
586 }
587
588 // Convert a color to the buffer pixel format.
589 static BUFFERTYPE convert_color(const Color &color) {
590 if constexpr (BUFFERPIXEL == PIXEL_MODE_8) {
591 return (color.red & 0xE0) | (color.g & 0xE0) >> 3 | color.b >> 6;
592 } else if constexpr (BUFFERPIXEL == PIXEL_MODE_16) {
593 if constexpr (IS_BIG_ENDIAN) {
594 return (color.r & 0xF8) | color.g >> 5 | (color.g & 0x1C) << 11 | (color.b & 0xF8) << 5;
595 } else {
596 return (color.r & 0xF8) << 8 | (color.g & 0xFC) << 3 | color.b >> 3;
597 }
598 }
599 return static_cast<BUFFERTYPE>(0);
600 }
601
602 BUFFERTYPE *buffer_{};
603 uint16_t x_low_{WIDTH};
604 uint16_t y_low_{HEIGHT};
605 uint16_t x_high_{0};
606 uint16_t y_high_{0};
607 uint16_t start_line_{0};
608 uint16_t end_line_{1};
609};
610
611} // namespace mipi_spi
612} // namespace esphome
uint8_t h
Definition bl0906.h:2
virtual void mark_failed()
Mark this component as failed.
bool is_failed() const
bool is_ready() const
virtual void setup()=0
virtual void digital_write(bool value)=0
An STL allocator that uses SPI or internal RAM.
Definition helpers.h:1647
T * allocate(size_t n)
Definition helpers.h:1667
display_writer_t writer_
Definition display.h:791
virtual void clear()
Clear the entire screen by filling it with OFF pixels.
Definition display.cpp:16
virtual void fill(Color color)
Fill the entire screen with the given color.
Definition display.cpp:15
DisplayPage * page_
Definition display.h:792
Rect get_clipping() const
Get the current the clipping rectangle.
Definition display.cpp:764
DisplayRotation rotation_
Definition display.h:790
const display_writer_t & get_writer() const
Definition display.cpp:896
Class for MIPI SPI displays with a buffer.
Definition mipi_spi.h:433
void draw_pixel_at(int x, int y, Color color) override
Definition mipi_spi.h:523
static constexpr unsigned BUFFER_HEIGHT
Definition mipi_spi.h:439
static BUFFERTYPE convert_color(const Color &color)
Definition mipi_spi.h:589
static constexpr unsigned BUFFER_WIDTH
Definition mipi_spi.h:438
void fill(Color color) override
Definition mipi_spi.h:545
static void rotate_coordinates(int &x, int &y)
Definition mipi_spi.h:573
Base class for MIPI SPI displays.
Definition mipi_spi.h:89
std::vector< GPIOPin * > enable_pins_
Definition mipi_spi.h:403
void update() override
Definition mipi_spi.h:92
void write_command_(uint8_t cmd, uint8_t data)
Definition mipi_spi.h:217
int get_height_internal() override
Definition mipi_spi.h:109
static PixelMode get_pixel_mode(display::ColorBitness bitness)
Definition mipi_spi.h:296
void set_addr_window_(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2)
Definition mipi_spi.h:277
int get_width_internal() override
Definition mipi_spi.h:108
void set_init_sequence(const std::vector< uint8_t > &sequence)
Definition mipi_spi.h:110
void set_reset_pin(GPIOPin *reset_pin)
Definition mipi_spi.h:95
void write_command_(uint8_t cmd)
Definition mipi_spi.h:218
void set_dc_pin(GPIOPin *dc_pin)
Definition mipi_spi.h:97
void set_invert_colors(bool invert_colors)
Definition mipi_spi.h:98
void setup() override
Definition mipi_spi.h:113
void set_brightness(uint8_t brightness)
Definition mipi_spi.h:102
void write_command_(uint8_t cmd, const uint8_t *bytes, size_t len)
Definition mipi_spi.h:221
void set_model(const char *model)
Definition mipi_spi.h:94
void write_display_data_(const uint8_t *ptr, size_t w, size_t h, size_t pad)
Writes a buffer to the display.
Definition mipi_spi.h:314
void dump_config() override
Definition mipi_spi.h:208
display::DisplayType get_display_type() override
Definition mipi_spi.h:106
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
Definition mipi_spi.h:193
void draw_pixel_at(int x, int y, Color color) override
Definition mipi_spi.h:93
void set_enable_pins(std::vector< GPIOPin * > enable_pins)
Definition mipi_spi.h:96
optional< uint8_t > brightness_
Definition mipi_spi.h:408
std::vector< uint8_t > init_sequence_
Definition mipi_spi.h:410
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.
Definition mipi_spi.h:343
bool has_value() const
Definition optional.h:92
value_type const & value() const
Definition optional.h:94
uint32_t data_rate_
Definition spi.h:410
The SPIDevice is what components using the SPI will create.
Definition spi.h:427
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)
Definition spi.h:471
uint16_t reset
Definition ina226.h:5
uint8_t duration
Definition msa3xx.h:0
@ DISPLAY_ROTATION_270_DEGREES
Definition display.h:138
@ DISPLAY_ROTATION_180_DEGREES
Definition display.h:137
@ DISPLAY_ROTATION_90_DEGREES
Definition display.h:136
const uint8_t MADCTL_CMD
Definition mipi_dsi.h:26
const uint8_t MADCTL_YFLIP
Definition mipi_dsi.h:37
const uint8_t INVERT_ON
Definition mipi_dsi.h:28
const uint8_t DISPLAY_ON
Definition mipi_dsi.h:29
const uint8_t MADCTL_MV
Definition mipi_dsi.h:35
const uint8_t MADCTL_MX
Definition mipi_dsi.h:33
const uint8_t MADCTL_MY
Definition mipi_dsi.h:34
const uint8_t MADCTL_XFLIP
Definition mipi_dsi.h:36
const uint8_t INVERT_OFF
Definition mipi_dsi.h:27
const uint8_t DELAY_FLAG
Definition mipi_dsi.h:31
const uint8_t SLEEP_OUT
Definition mipi_dsi.h:24
const uint8_t SW_RESET_CMD
Definition mipi_dsi.h:23
const uint8_t MADCTL_BGR
Definition mipi_dsi.h:32
void internal_dump_config(const char *model, int width, int height, int offset_width, int offset_height, uint8_t madctl, bool invert_colors, int display_bits, bool is_big_endian, const optional< uint8_t > &brightness, GPIOPin *cs, GPIOPin *reset, GPIOPin *dc, int spi_mode, uint32_t data_rate, int bus_width)
Definition mipi_spi.cpp:6
Providing packet encoding functions for exchanging data with a remote host.
Definition a01nyub.cpp:7
std::string size_t len
Definition helpers.h:692
char * format_hex_pretty_to(char *buffer, size_t buffer_size, const uint8_t *data, size_t length, char separator)
Format byte array as uppercase hex to buffer (base implementation).
Definition helpers.cpp:353
constexpr size_t format_hex_pretty_size(size_t byte_count)
Calculate buffer size needed for format_hex_pretty_to with separator: "XX:XX:...:XX\0".
Definition helpers.h:978
void IRAM_ATTR HOT delay(uint32_t ms)
Definition core.cpp:26
uint32_t IRAM_ATTR HOT millis()
Definition core.cpp:25
uint8_t red
Definition color.h:31
uint8_t g
Definition color.h:34
uint8_t b
Definition color.h:38
uint8_t r
Definition color.h:30
uint8_t pad
uint16_t x
Definition tt21100.cpp:5
uint16_t y
Definition tt21100.cpp:6