1#ifdef USE_ESP32_VARIANT_ESP32P4
12static constexpr size_t MIPI_DSI_MAX_CMD_LOG_BYTES = 64;
14static bool notify_refresh_ready(esp_lcd_panel_handle_t panel, esp_lcd_dpi_panel_event_data_t *edata,
void *user_ctx) {
15 SemaphoreHandle_t sem =
static_cast<SemaphoreHandle_t
>(user_ctx);
16 BaseType_t need_yield = pdFALSE;
17 xSemaphoreGiveFromISR(sem, &need_yield);
18 return (need_yield == pdTRUE);
27 ESP_LOGCONFIG(TAG,
"Running Setup");
32 pin->digital_write(
true);
37 esp_lcd_dsi_bus_config_t bus_config = {
44 auto err = esp_lcd_new_dsi_bus(&bus_config, &this->
bus_handle_);
46 this->
smark_failed(LOG_STR(
"lcd_new_dsi_bus failed"), err);
49 esp_lcd_dbi_io_config_t dbi_config = {
56 this->
smark_failed(LOG_STR(
"new_panel_io_dbi failed"), err);
60#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(6, 0, 0)
61 auto color_format = LCD_COLOR_FMT_RGB565;
63 color_format = LCD_COLOR_FMT_RGB888;
65 esp_lcd_dpi_panel_config_t dpi_config = {.virtual_channel = 0,
66 .dpi_clk_src = MIPI_DSI_DPI_CLK_SRC_DEFAULT,
68 .in_color_format = color_format,
70 auto pixel_format = LCD_COLOR_PIXEL_FORMAT_RGB565;
72 pixel_format = LCD_COLOR_PIXEL_FORMAT_RGB888;
74 esp_lcd_dpi_panel_config_t dpi_config = {.virtual_channel = 0,
75 .dpi_clk_src = MIPI_DSI_DPI_CLK_SRC_DEFAULT,
77 .pixel_format = pixel_format,
92#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(6, 0, 0)
99 this->
smark_failed(LOG_STR(
"esp_lcd_new_panel_dpi failed"), err);
102#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(6, 0, 0)
103 err = esp_lcd_dpi_panel_enable_dma2d(this->
handle_);
105 this->
smark_failed(LOG_STR(
"esp_lcd_dpi_panel_enable_dma2d failed"), err);
120 auto when =
millis() + 120;
121 err = esp_lcd_panel_init(this->
handle_);
123 this->
smark_failed(LOG_STR(
"esp_lcd_init failed"), err);
129 while (index !=
len) {
130 if (
len - index < 2) {
131 this->
mark_failed(LOG_STR(
"Malformed init sequence"));
134 uint8_t cmd =
seq[index++];
135 uint8_t
x =
seq[index++];
137 ESP_LOGD(TAG,
"Delay %dms", cmd);
140 uint8_t num_args =
x & 0x7F;
141 if (
len - index < num_args) {
142 this->
mark_failed(LOG_STR(
"Malformed init sequence"));
152 const auto *
ptr =
seq + index;
153#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERY_VERBOSE
156 ESP_LOGVV(TAG,
"Command %02X, length %d, byte(s) %s", cmd, num_args,
158 err = esp_lcd_panel_io_tx_param(this->
io_handle_, cmd,
ptr, num_args);
160 this->
smark_failed(LOG_STR(
"lcd_panel_io_tx_param failed"), err);
168 this->
io_lock_ = xSemaphoreCreateBinary();
169 esp_lcd_dpi_panel_event_callbacks_t cbs = {
170 .on_color_trans_done = notify_refresh_ready,
173 err = (esp_lcd_dpi_panel_register_event_callbacks(this->
handle_, &cbs, this->
io_lock_));
175 this->
smark_failed(LOG_STR(
"Failed to register callbacks"), err);
179 ESP_LOGCONFIG(TAG,
"MIPI DSI setup complete");
189 }
else if (this->
page_ !=
nullptr) {
208 this->
width_ - w - this->x_low_);
210 this->x_low_ = this->
width_;
219 if (
w <= 0 ||
h <= 0)
228 if (this->
buffer_ !=
nullptr) {
230 const int first_col = std::max(0, -x_start), end_col = std::min(
w,
static_cast<int>(this->
width_) - x_start);
231 const int first_row = std::max(0, -
y_start), end_row = std::min(
h,
static_cast<int>(this->
height_) - y_start);
232 if (first_col >= end_col || first_row >= end_row)
236 for (
int y = first_row;
y != end_row;
y++) {
237 memcpy(this->
buffer_ + ((y_start +
y) * this->
width_ + x_start + first_col) * bytes_per_pixel,
239 (end_col - first_col) * bytes_per_pixel);
242 this->
mark_dirty_(x_start + first_col,
y_start + first_row, end_col - first_col, end_row - first_row);
261 xSemaphoreTake(this->
io_lock_, portMAX_DELAY);
265 for (
int y = 0;
y !=
h;
y++) {
270 xSemaphoreTake(this->
io_lock_, portMAX_DELAY);
274 ESP_LOGE(TAG,
"lcd_lcd_panel_draw_bitmap failed: %s",
esp_err_to_name(err));
285 RAMAllocator<uint8_t> allocator;
287 if (this->
buffer_ ==
nullptr) {
288 this->
mark_failed(LOG_STR(
"Could not allocate buffer for display!"));
300 const int right =
static_cast<int>(this->
width_) - 1;
301 const int bottom =
static_cast<int>(this->
height_) - 1;
302 const int left = std::clamp(std::min(x1, x2), 0, right);
303 const int top = std::clamp(std::min(y1, y2), 0, bottom);
304 x2 = std::clamp(std::max(x1, x2), 0, right);
305 y2 = std::clamp(std::max(y1, y2), 0, bottom);
333 auto *ptr_16 =
reinterpret_cast<uint16_t *
>(this->
buffer_);
335 if (ptr_16[
pos] == new_color)
337 ptr_16[
pos] = new_color;
342 this->
buffer_[pos * 3] = color.b;
343 this->
buffer_[pos * 3 + 1] = color.g;
344 this->
buffer_[pos * 3 + 2] = color.r;
365 Display::fill(color);
371 auto *ptr_16 =
reinterpret_cast<uint16_t *
>(this->
buffer_);
373 std::fill_n(ptr_16, this->
width_ * this->
height_, new_color);
379 this->
buffer_[i * 3 + 0] = color.b;
380 this->
buffer_[i * 3 + 1] = color.g;
381 this->
buffer_[i * 3 + 2] = color.r;
414static const uint8_t PIXEL_MODES[] = {0, 16, 18, 24};
422 "\n Rotation: %d degrees"
424 "\n Lane Bit Rate: %.0fMbps"
425 "\n HSync Pulse Width: %u"
426 "\n HSync Back Porch: %u"
427 "\n HSync Front Porch: %u"
428 "\n VSync Pulse Width: %u"
429 "\n VSync Back Porch: %u"
430 "\n VSync Front Porch: %u"
431 "\n Buffer Color Depth: %d bit"
432 "\n Display Pixel Mode: %d bit"
433 "\n Invert Colors: %s"
434 "\n Pixel Clock: %.1fMHz",
void mark_failed()
Mark this component as failed.
virtual void digital_write(bool value)=0
int int int const uint8_t ColorOrder ColorBitness bitness
virtual void clear()
Clear the entire screen by filling it with OFF pixels.
int int int const uint8_t ColorOrder ColorBitness bool int int y_offset
int int int const uint8_t ColorOrder ColorBitness bool int int int x_pad
int int int const uint8_t * ptr
bool ESPHOME_ALWAYS_INLINE is_point_clipped(int x, int y) const
Whether (x, y) falls outside the active clipping rectangle.
int int int const uint8_t ColorOrder ColorBitness bool big_endian
Rect get_clipping() const
Get the current the clipping rectangle.
int int int const uint8_t ColorOrder ColorBitness bool int x_offset
DisplayRotation rotation_
virtual void draw_pixels_internal(int x_start, int y_start, int w, int h, const uint8_t *ptr, ColorBitness bitness, bool big_endian, int x_offset, int y_offset, int x_pad)
Draws a block for draw_pixels_at(); the parameters are the same.
const display_writer_t & get_writer() const
void mark_dirty_(int x_start, int y_start, int w, int h)
display::ColorBitness color_depth_
uint16_t hsync_front_porch_
esp_lcd_panel_handle_t handle_
int get_height_internal() override
uint16_t hsync_pulse_width_
esp_lcd_panel_io_handle_t io_handle_
uint16_t vsync_front_porch_
uint16_t to_panel_565_(Color color) const
Pack a colour as the 565 value the panel's byte order expects in memory.
int get_width_internal() override
void draw_pixel_at(int x, int y, Color color) override
std::vector< GPIOPin * > enable_pins_
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)
void draw_pixels_internal(int x_start, int y_start, int w, int h, const uint8_t *ptr, display::ColorBitness bitness, bool big_endian, int x_offset, int y_offset, int x_pad) override
SemaphoreHandle_t io_lock_
uint16_t vsync_back_porch_
void smark_failed(const LogString *message, esp_err_t err)
esp_lcd_dsi_bus_handle_t bus_handle_
void fill(Color color) override
int get_height() override
const uint8_t * init_sequence_
void flush_dirty_()
Send the region touched since the last flush to the panel.
void dump_config() override
size_t init_sequence_len_
uint16_t hsync_back_porch_
void rotate_(int &x, int &y) const
uint16_t vsync_pulse_width_
const LogString * message
@ DISPLAY_ROTATION_0_DEGREES
@ DISPLAY_ROTATION_270_DEGREES
@ DISPLAY_ROTATION_180_DEGREES
@ DISPLAY_ROTATION_90_DEGREES
const char * esp_err_to_name(esp_err_t err)
const uint8_t SW_RESET_CMD
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()