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> {
107 if (this->
dc_pin_ !=
nullptr) {
113 pin->digital_write(
true);
125 auto when =
millis() + 120;
129 while (index != vec.size()) {
130 if (vec.size() - index < 2) {
131 esph_log_e(TAG,
"Malformed init sequence");
135 uint8_t cmd = vec[index++];
136 uint8_t
x = vec[index++];
137 if (
x == DELAY_FLAG) {
138 esph_log_d(TAG,
"Delay %dms", cmd);
141 uint8_t num_args =
x & 0x7F;
142 if (vec.size() - index < num_args) {
143 esph_log_e(TAG,
"Malformed init sequence");
147 auto arg_byte = vec[index];
153 esph_log_d(TAG,
"Sleep %dms",
duration);
171 const auto *ptr = vec.data() + index;
172 esph_log_d(TAG,
"Command %02X, length %d, byte %02X", cmd, num_args, arg_byte);
175 if (cmd == SLEEP_OUT)
189 if (w <= 0 ||
h <= 0)
191 if (
get_pixel_mode(bitness) != BUFFERPIXEL || big_endian != IS_BIG_ENDIAN) {
193 esph_log_e(TAG,
"Unsupported color depth or bit order");
196 this->
write_to_display_(x_start, y_start, w,
h,
reinterpret_cast<const BUFFERTYPE *
>(ptr), x_offset, y_offset,
206 this->
model_, WIDTH, HEIGHT);
207 if constexpr (OFFSET_WIDTH != 0)
208 esph_log_config(TAG,
" Offset width: %u", OFFSET_WIDTH);
209 if constexpr (OFFSET_HEIGHT != 0)
210 esph_log_config(TAG,
" Offset height: %u", OFFSET_HEIGHT);
215 " Invert colors: %s\n"
217 " Display pixels: %d bits\n"
219 YESNO(this->
madctl_ & MADCTL_MV), YESNO(this->
madctl_ & (MADCTL_MX | MADCTL_XFLIP)),
221 this->
madctl_ & MADCTL_BGR ?
"BGR" :
"RGB", DISPLAYPIXEL * 8, IS_BIG_ENDIAN ?
"Big" :
"Little");
224 if (this->
cs_ !=
nullptr)
225 esph_log_config(TAG,
" CS Pin: %s", this->
cs_->
dump_summary().c_str());
232 " SPI Data rate: %dMHz\n"
233 " SPI Bus width: %d",
234 this->
mode_,
static_cast<unsigned>(this->
data_rate_ / 1000000), BUS_TYPE);
278 for (
size_t i = 0; i !=
len; i++) {
298 esph_log_v(TAG,
"Set addr %d/%d, %d/%d", x1, y1, x2, y2);
305 put16_be(buf + 2, y2);
308 put16_be(buf + 2, x2);
343 for (
size_t y = 0;
y !=
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 !=
h;
y++) {
376 for (
size_t x = 0;
x != 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) {
450class MipiSpiBuffer :
public MipiSpi<BUFFERTYPE, BUFFERPIXEL, IS_BIG_ENDIAN, DISPLAYPIXEL, BUS_TYPE, WIDTH, HEIGHT,
451 OFFSET_WIDTH, OFFSET_HEIGHT> {
456 MipiSpi<BUFFERTYPE, BUFFERPIXEL, IS_BIG_ENDIAN, DISPLAYPIXEL, BUS_TYPE, WIDTH, HEIGHT, OFFSET_WIDTH,
460 " Buffer pixels: %d bits\n"
461 " Buffer fraction: 1/%d\n"
462 " Buffer bytes: %zu\n"
463 " Draw rounding: %u",
464 this->
rotation_, BUFFERPIXEL * 8, FRACTION,
sizeof(BUFFERTYPE) * WIDTH * HEIGHT / FRACTION,
469 MipiSpi<BUFFERTYPE, BUFFERPIXEL, IS_BIG_ENDIAN, DISPLAYPIXEL, BUS_TYPE, WIDTH, HEIGHT, OFFSET_WIDTH,
473 if (this->
buffer_ ==
nullptr) {
479#if ESPHOME_LOG_LEVEL == ESPHOME_LOG_LEVEL_VERBOSE
488#if ESPHOME_LOG_LEVEL == ESPHOME_LOG_LEVEL_VERBOSE
495 if (this->
page_ !=
nullptr) {
502#if ESPHOME_LOG_LEVEL == ESPHOME_LOG_LEVEL_VERBOSE
503 esph_log_v(TAG,
"Drawing from line %d took %dms", this->
start_line_,
millis() - lap);
508 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_,
521 this->x_low_ = WIDTH;
522 this->y_low_ = HEIGHT;
525#if ESPHOME_LOG_LEVEL == ESPHOME_LOG_LEVEL_VERBOSE
526 esph_log_v(TAG,
"Write to display took %dms",
millis() - lap);
530#if ESPHOME_LOG_LEVEL == ESPHOME_LOG_LEVEL_VERBOSE
531 esph_log_v(TAG,
"Total update took %dms",
millis() - now);
598 return (color.
red & 0xE0) | (color.
g & 0xE0) >> 3 | color.
b >> 6;
600 if constexpr (IS_BIG_ENDIAN) {
601 return (color.
r & 0xF8) | color.
g >> 5 | (color.
g & 0x1C) << 11 | (color.
b & 0xF8) << 5;
603 return (color.
r & 0xF8) << 8 | (color.
g & 0xFC) << 3 | color.
b >> 3;
606 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.
void clear()
Clear the entire screen by filling it with OFF pixels.
optional< display_writer_t > writer_
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.
int get_height() override
void draw_pixel_at(int x, int y, Color color) override
void fill(Color color) override
BUFFERTYPE convert_color_(Color &color) const
void dump_config() override
void rotate_coordinates_(int &x, int &y) const
Base class for MIPI SPI displays.
std::vector< GPIOPin * > enable_pins_
void set_draw_rounding(unsigned rounding)
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()