1#ifdef USE_ESP32_VARIANT_ESP32P4
10static constexpr size_t MIPI_DSI_MAX_CMD_LOG_BYTES = 64;
12static bool notify_refresh_ready(esp_lcd_panel_handle_t panel, esp_lcd_dpi_panel_event_data_t *edata,
void *user_ctx) {
13 auto sem =
static_cast<SemaphoreHandle_t
>(user_ctx);
14 BaseType_t need_yield = pdFALSE;
15 xSemaphoreGiveFromISR(sem, &need_yield);
16 return (need_yield == pdTRUE);
20 ESP_LOGE(TAG,
"%s: %s", LOG_STR_ARG(
message), esp_err_to_name(err));
25 ESP_LOGCONFIG(TAG,
"Running Setup");
30 pin->digital_write(
true);
35 esp_lcd_dsi_bus_config_t bus_config = {
39 .phy_clk_src = MIPI_DSI_PHY_CLK_SRC_DEFAULT,
42 auto err = esp_lcd_new_dsi_bus(&bus_config, &this->
bus_handle_);
44 this->
smark_failed(LOG_STR(
"lcd_new_dsi_bus failed"), err);
47 esp_lcd_dbi_io_config_t dbi_config = {
54 this->
smark_failed(LOG_STR(
"new_panel_io_dbi failed"), err);
58#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(6, 0, 0)
59 auto color_format = LCD_COLOR_FMT_RGB565;
61 color_format = LCD_COLOR_FMT_RGB888;
63 esp_lcd_dpi_panel_config_t dpi_config = {.virtual_channel = 0,
64 .dpi_clk_src = MIPI_DSI_DPI_CLK_SRC_DEFAULT,
66 .in_color_format = color_format,
68 auto pixel_format = LCD_COLOR_PIXEL_FORMAT_RGB565;
70 pixel_format = LCD_COLOR_PIXEL_FORMAT_RGB888;
72 esp_lcd_dpi_panel_config_t dpi_config = {.virtual_channel = 0,
73 .dpi_clk_src = MIPI_DSI_DPI_CLK_SRC_DEFAULT,
75 .pixel_format = pixel_format,
90#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(6, 0, 0)
97 this->
smark_failed(LOG_STR(
"esp_lcd_new_panel_dpi failed"), err);
100#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(6, 0, 0)
101 err = esp_lcd_dpi_panel_enable_dma2d(this->
handle_);
103 this->
smark_failed(LOG_STR(
"esp_lcd_dpi_panel_enable_dma2d failed"), err);
118 auto when =
millis() + 120;
119 err = esp_lcd_panel_init(this->
handle_);
121 this->
smark_failed(LOG_STR(
"esp_lcd_init failed"), err);
126 while (index != vec.size()) {
127 if (vec.size() - index < 2) {
128 this->
mark_failed(LOG_STR(
"Malformed init sequence"));
131 uint8_t cmd = vec[index++];
132 uint8_t
x = vec[index++];
134 ESP_LOGD(TAG,
"Delay %dms", cmd);
137 uint8_t num_args =
x & 0x7F;
138 if (vec.size() - index < num_args) {
139 this->
mark_failed(LOG_STR(
"Malformed init sequence"));
149 const auto *ptr = vec.data() + index;
150#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERY_VERBOSE
153 ESP_LOGVV(TAG,
"Command %02X, length %d, byte(s) %s", cmd, num_args,
155 err = esp_lcd_panel_io_tx_param(this->
io_handle_, cmd, ptr, num_args);
157 this->
smark_failed(LOG_STR(
"lcd_panel_io_tx_param failed"), err);
165 this->
io_lock_ = xSemaphoreCreateBinary();
166 esp_lcd_dpi_panel_event_callbacks_t cbs = {
167 .on_color_trans_done = notify_refresh_ready,
170 err = (esp_lcd_dpi_panel_register_event_callbacks(this->
handle_, &cbs, this->
io_lock_));
172 this->
smark_failed(LOG_STR(
"Failed to register callbacks"), err);
176 ESP_LOGCONFIG(TAG,
"MIPI DSI setup complete");
185 }
else if (this->
page_ !=
nullptr) {
198 this->
width_ - w - this->x_low_);
200 this->x_low_ = this->
width_;
208 if (w <= 0 ||
h <= 0)
213 display::Display::draw_pixels_at(x_start, y_start, w,
h, ptr, order, bitness, big_endian, x_offset, y_offset,
222 esp_err_t err = ESP_OK;
224 auto stride = (x_offset + w + x_pad) * bytes_per_pixel;
225 ptr += y_offset * stride + x_offset * bytes_per_pixel;
227 if (x_offset == 0 && x_pad == 0) {
228 err = esp_lcd_panel_draw_bitmap(this->
handle_, x_start, y_start, x_start + w, y_start +
h, ptr);
229 xSemaphoreTake(this->
io_lock_, portMAX_DELAY);
233 for (
int y = 0;
y !=
h;
y++) {
234 err = esp_lcd_panel_draw_bitmap(this->
handle_, x_start,
y + y_start, x_start + w,
y + y_start + 1, ptr);
238 xSemaphoreTake(this->
io_lock_, portMAX_DELAY);
242 ESP_LOGE(TAG,
"lcd_lcd_panel_draw_bitmap failed: %s", esp_err_to_name(err));
252 RAMAllocator<uint8_t> allocator;
254 if (this->
buffer_ ==
nullptr) {
255 this->
mark_failed(LOG_STR(
"Could not allocate buffer for display!"));
290 auto *ptr_16 =
reinterpret_cast<uint16_t *
>(this->
buffer_);
291 uint8_t hi_byte =
static_cast<uint8_t
>(color.r & 0xF8) | (color.g >> 5);
292 uint8_t lo_byte =
static_cast<uint8_t
>((color.g & 0x1C) << 3) | (color.b >> 3);
293 uint16_t new_color = lo_byte | (hi_byte << 8);
294 if (ptr_16[
pos] == new_color)
296 ptr_16[
pos] = new_color;
301 this->
buffer_[pos * 3] = color.b;
302 this->
buffer_[pos * 3 + 1] = color.g;
303 this->
buffer_[pos * 3 + 2] = color.r;
305 this->
buffer_[pos * 3] = color.r;
306 this->
buffer_[pos * 3 + 1] = color.g;
307 this->
buffer_[pos * 3 + 2] = color.b;
329 Display::fill(color);
335 auto *ptr_16 =
reinterpret_cast<uint16_t *
>(this->
buffer_);
336 uint8_t hi_byte =
static_cast<uint8_t
>(color.r & 0xF8) | (color.g >> 5);
337 uint8_t lo_byte =
static_cast<uint8_t
>((color.g & 0x1C) << 3) | (color.b >> 3);
338 uint16_t new_color = lo_byte | (hi_byte << 8);
339 std::fill_n(ptr_16, this->
width_ * this->
height_, new_color);
346 this->
buffer_[i * 3 + 0] = color.b;
347 this->
buffer_[i * 3 + 1] = color.g;
348 this->
buffer_[i * 3 + 2] = color.r;
352 this->
buffer_[i * 3 + 0] = color.r;
353 this->
buffer_[i * 3 + 1] = color.g;
354 this->
buffer_[i * 3 + 2] = color.b;
387static const uint8_t PIXEL_MODES[] = {0, 16, 18, 24};
395 "\n Rotation: %d degrees"
397 "\n Lane Bit Rate: %.0fMbps"
398 "\n HSync Pulse Width: %u"
399 "\n HSync Back Porch: %u"
400 "\n HSync Front Porch: %u"
401 "\n VSync Pulse Width: %u"
402 "\n VSync Back Porch: %u"
403 "\n VSync Front Porch: %u"
404 "\n Buffer Color Depth: %d bit"
405 "\n Display Pixel Mode: %d bit"
406 "\n Invert Colors: %s"
407 "\n Pixel Clock: %.1fMHz",
void mark_failed()
Mark this component as failed.
virtual void digital_write(bool value)=0
static uint16_t color_to_565(Color color, ColorOrder color_order=ColorOrder::COLOR_ORDER_RGB)
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_
virtual void draw_pixels_at(int x_start, int y_start, int w, int h, const uint8_t *ptr, ColorOrder order, ColorBitness bitness, bool big_endian, int x_offset, int y_offset, int x_pad)
Given an array of pixels encoded in the nominated format, draw these into the display's buffer.
const display_writer_t & get_writer() const
uint16_t vsync_front_porch_
void fill(Color color) override
uint16_t hsync_front_porch_
uint16_t hsync_back_porch_
display::ColorOrder color_mode_
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 dump_config() override
std::vector< GPIOPin * > enable_pins_
void smark_failed(const LogString *message, esp_err_t err)
uint16_t vsync_pulse_width_
display::ColorBitness color_depth_
uint16_t hsync_pulse_width_
SemaphoreHandle_t io_lock_
void write_to_display_(int x_start, int y_start, int w, int h, const uint8_t *ptr, int x_offset, int y_offset, int x_pad)
esp_lcd_panel_io_handle_t io_handle_
int get_height() override
void draw_pixel_at(int x, int y, Color color) override
uint16_t vsync_back_porch_
int get_width_internal() override
esp_lcd_dsi_bus_handle_t bus_handle_
std::vector< uint8_t > init_sequence_
int get_height_internal() override
esp_lcd_panel_handle_t handle_
@ DISPLAY_ROTATION_0_DEGREES
@ DISPLAY_ROTATION_270_DEGREES
@ DISPLAY_ROTATION_180_DEGREES
@ DISPLAY_ROTATION_90_DEGREES
const uint8_t SW_RESET_CMD
Providing packet encoding functions for exchanging data with a remote host.
constexpr T convert_big_endian(T val)
Convert a value between host byte order and big endian (most significant byte first) order.
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).
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".
void HOT delay(uint32_t ms)
uint32_t IRAM_ATTR HOT millis()