1#ifdef USE_ESP32_VARIANT_ESP32S3
6#include "esp_lcd_panel_rgb.h"
11static const uint8_t DELAY_FLAG = 0xFF;
14static constexpr size_t MIPI_RGB_MAX_CMD_LOG_BYTES = 64;
15static constexpr uint8_t MADCTL_MY = 0x80;
16static constexpr uint8_t MADCTL_MX = 0x40;
17static constexpr uint8_t MADCTL_MV = 0x20;
18static constexpr uint8_t MADCTL_ML = 0x10;
19static constexpr uint8_t MADCTL_BGR = 0x08;
20static constexpr uint8_t MADCTL_XFLIP = 0x02;
21static constexpr uint8_t MADCTL_YFLIP = 0x01;
27 pin->digital_write(
true);
51 this->
write(value, 9);
63 this->
write(value | 0x100, 9);
78 while (index != vec.size()) {
79 if (vec.size() - index < 2) {
80 this->
mark_failed(LOG_STR(
"Malformed init sequence"));
83 uint8_t cmd = vec[index++];
84 uint8_t
x = vec[index++];
85 if (
x == DELAY_FLAG) {
86 ESP_LOGD(TAG,
"Delay %dms", cmd);
89 uint8_t num_args =
x & 0x7F;
90 if (vec.size() - index < num_args) {
91 this->
mark_failed(LOG_STR(
"Malformed init sequence"));
97 const auto *ptr = vec.data() + index;
99 ESP_LOGD(TAG,
"Write command %02X, length %d, byte(s) %s", cmd, num_args,
103 while (num_args-- != 0)
116 LOG_PIN(
" CS Pin: ", this->
cs_);
117 LOG_PIN(
" DC Pin: ", this->
dc_pin_);
119 " SPI Data rate: %uMHz"
123 "\n Color Order: %s",
124 (
unsigned) (this->
data_rate_ / 1000000), YESNO(this->
madctl_ & (MADCTL_XFLIP | MADCTL_MX)),
125 YESNO(this->
madctl_ & (MADCTL_YFLIP | MADCTL_MY | MADCTL_ML)), YESNO(this->
madctl_ & MADCTL_MV),
126 this->
madctl_ & MADCTL_BGR ?
"BGR" :
"RGB");
137 esp_lcd_rgb_panel_config_t config{};
138 config.flags.fb_in_psram = 1;
139 config.bounce_buffer_size_px = this->
width_ * 10;
141 config.timings.h_res = this->
width_;
142 config.timings.v_res = this->
height_;
151 config.clk_src = LCD_CLK_SRC_PLL160M;
153 for (
size_t i = 0; i != data_pin_count; i++) {
156 config.data_width = data_pin_count;
157 config.disp_gpio_num = -1;
163 config.de_gpio_num = -1;
166 esp_err_t err = esp_lcd_new_rgb_panel(&config, &this->
handle_);
168 err = esp_lcd_panel_reset(this->
handle_);
170 err = esp_lcd_panel_init(this->
handle_);
172 ESP_LOGE(TAG,
"lcd setup failed: %s", esp_err_to_name(err));
175 ESP_LOGCONFIG(TAG,
"MipiRgb setup complete");
180 esp_lcd_rgb_panel_restart(this->
handle_);
191 }
else if (this->
page_ !=
nullptr) {
204 this->x_low_, this->y_low_, this->
width_ - w - this->x_low_);
206 this->x_low_ = this->
width_;
219 Display::draw_pixels_at(x_start, y_start, w,
h, ptr, order, bitness, big_endian, x_offset, y_offset, x_pad);
221 this->
width_ - w - x_start);
229 esp_err_t err = ESP_OK;
230 auto stride = (x_offset + w + x_pad) * 2;
231 ptr += y_offset * stride + x_offset * 2;
233 if (x_offset == 0 && x_pad == 0) {
234 err = esp_lcd_panel_draw_bitmap(this->
handle_, x_start, y_start, x_start + w, y_start +
h, ptr);
237 for (
int y = 0;
y !=
h;
y++) {
238 err = esp_lcd_panel_draw_bitmap(this->
handle_, x_start,
y + y_start, x_start + w,
y + y_start + 1, ptr);
245 ESP_LOGE(TAG,
"lcd_lcd_panel_draw_bitmap failed: %s", esp_err_to_name(err));
256 if (this->
buffer_ ==
nullptr) {
257 this->
mark_failed(LOG_STR(
"Could not allocate buffer for display!"));
288 size_t pos = (
y * this->
width_) + x;
289 uint8_t hi_byte =
static_cast<uint8_t
>(color.
r & 0xF8) | (color.
g >> 5);
290 uint8_t lo_byte =
static_cast<uint8_t
>((color.
g & 0x1C) << 3) | (color.
b >> 3);
291 uint16_t new_color = hi_byte | (lo_byte << 8);
292 if (this->
buffer_[pos] == new_color)
294 this->
buffer_[pos] = new_color;
311 Display::fill(color);
315 auto *ptr_16 =
reinterpret_cast<uint16_t *
>(this->
buffer_);
316 uint8_t hi_byte =
static_cast<uint8_t
>(color.
r & 0xF8) | (color.
g >> 5);
317 uint8_t lo_byte =
static_cast<uint8_t
>((color.
g & 0x1C) << 3) | (color.
b >> 3);
318 uint16_t new_color = lo_byte | (hi_byte << 8);
319 std::fill_n(ptr_16, this->
width_ * this->
height_, new_color);
346static std::string get_pin_name(
GPIOPin *pin) {
353 for (uint8_t i = start; i !=
end; i++) {
354 ESP_LOGCONFIG(TAG,
" %s pin %d: %s", name, offset++, this->
data_pins_[i]->dump_summary().c_str());
364 "\n Rotation: %d degrees"
365 "\n PCLK Inverted: %s"
366 "\n HSync Pulse Width: %u"
367 "\n HSync Back Porch: %u"
368 "\n HSync Front Porch: %u"
369 "\n VSync Pulse Width: %u"
370 "\n VSync Back Porch: %u"
371 "\n VSync Front Porch: %u"
372 "\n Invert Colors: %s"
373 "\n Pixel Clock: %uMHz"
virtual void mark_failed()
Mark this component as failed.
virtual std::string dump_summary() const =0
virtual void digital_write(bool value)=0
virtual uint8_t get_pin() const =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
InternalGPIOPin * de_pin_
std::vector< GPIOPin * > enable_pins_
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
uint16_t hsync_pulse_width_
uint16_t hsync_front_porch_
uint16_t vsync_back_porch_
esp_lcd_panel_handle_t handle_
int get_height() override
InternalGPIOPin * hsync_pin_
void dump_config() override
uint16_t vsync_front_porch_
int get_height_internal() override
uint16_t vsync_pulse_width_
InternalGPIOPin * data_pins_[16]
void draw_pixel_at(int x, int y, Color color) override
InternalGPIOPin * vsync_pin_
void dump_pins_(uint8_t start, uint8_t end, const char *name, uint8_t offset)
InternalGPIOPin * pclk_pin_
uint16_t hsync_back_porch_
int get_width_internal() override
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 write_data_(uint8_t value)
void write_init_sequence_()
this relies upon the init sequence being well-formed, which is guaranteed by the Python init code.
void write_command_(uint8_t value)
std::vector< uint8_t > init_sequence_
void spi_setup() override
void write_byte(uint8_t data)
void write(uint16_t data, size_t num_bits)
@ DISPLAY_ROTATION_0_DEGREES
@ DISPLAY_ROTATION_270_DEGREES
@ DISPLAY_ROTATION_180_DEGREES
@ DISPLAY_ROTATION_90_DEGREES
Providing packet encoding functions for exchanging data with a remote host.
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 IRAM_ATTR HOT delay(uint32_t ms)