Skip to content

Commit c42c959

Browse files
authored
Initial LCD support. (#568)
* Initial LCD support. The esp32p4 supports LCDs through DSI. This is the initial LCD support for esp32p4. * Rename peripheral to DSI, embedded_graphics support. * Delete lcd.rs. * Rename dsi.rs back to lcd.rs.
1 parent bc48639 commit c42c959

File tree

6 files changed

+1629
-0
lines changed

6 files changed

+1629
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
3939
- Removed the modem peripheral for esp32p4
4040
- LDO support for esp32p4
4141
- Support for `PLL_F48M` UART clock source on ESP32-H2
42+
- LCD driver support; DSI peripheral support with the LCD driver for esp32p4
4243

4344
### Fixed
4445
- Fix pcnt_rotary_encoder example for esp32

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ pcnt-legacy = []
5353
# - When enabled, the code for the legacy driver will be compiled.
5454
# - When disabled the code for the new driver will be compiled.
5555
timer-legacy = []
56+
embedded-graphics = ["dep:embedded-graphics-core"]
5657

5758
[dependencies]
5859
nb = "1"
@@ -70,6 +71,7 @@ enumset = { version = "1.1.4", default-features = false }
7071
log = { version = "0.4", default-features = false }
7172
atomic-waker = { version = "1.1.1", default-features = false }
7273
embassy-sync = "0.7"
74+
embedded-graphics-core = { version = "0.4", optional = true }
7375

7476
[build-dependencies]
7577
embuild = "0.33"

examples/lcd_dsi_basic.rs

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
//! Basic LCD DSI example for ESP32-P4
2+
//!
3+
//! This example shows how to:
4+
//! - Configure the LCD peripheral for a DSI panel
5+
//! - Create a vendor-specific control panel (ILI9881C over DBI)
6+
//! - Initialize the panel
7+
//! - Create a DPI panel for frame updates
8+
//! - Draw a simple bitmap
9+
//!
10+
//! Requirements:
11+
//! - Target: ESP32-P4 (`ESP_IDF_TARGET=esp32p4`)
12+
//! - ESP-IDF must have the ILI9881C DSI panel component enabled
13+
//! - A compatible 1024×600 MIPI-DSI display connected to the LCD peripheral
14+
15+
#![allow(unknown_lints)]
16+
#![allow(unexpected_cfgs)]
17+
18+
#[cfg(esp32p4)]
19+
mod example {
20+
use std::time::Duration;
21+
22+
use esp_idf_hal::lcd::*;
23+
use esp_idf_hal::ldo::*;
24+
use esp_idf_hal::peripherals::Peripherals;
25+
26+
use esp_idf_sys::*;
27+
28+
pub fn run() -> anyhow::Result<()> {
29+
// Link ESP-IDF patches (required for examples)
30+
esp_idf_hal::sys::link_patches();
31+
32+
let peripherals = Peripherals::take()?;
33+
34+
// Configure LDO3 for MIPI D-PHY supply (typically 2.5 V).
35+
//
36+
// NOTE: Adjust the voltage to match your board's design and panel
37+
// requirements. 2.5 V is a common value for the DSI PHY supply.
38+
let ldo_cfg = LdoChannelConfig::new(2500);
39+
let _ldo3 = LdoChannel::new(&peripherals.ldo3, &ldo_cfg)?;
40+
41+
// Give the LDO some time to stabilize before enabling the panel.
42+
std::thread::sleep(Duration::from_millis(20));
43+
44+
// Configure video timing for a 1024×600 panel.
45+
// Adjust these values to match your panel's datasheet.
46+
let video_timing = VideoTiming::new(1024, 600)
47+
.hsync_back_porch(100)
48+
.hsync_pulse_width(100)
49+
.hsync_front_porch(100)
50+
.vsync_back_porch(10)
51+
.vsync_pulse_width(10)
52+
.vsync_front_porch(10);
53+
54+
// High-level LCD configuration:
55+
// - 2 DSI data lanes at 1250 Mbps
56+
// - RGB888 pixel format
57+
// - DPI clock at 48 MHz
58+
let config = LcdConfig::new(
59+
video_timing,
60+
2, // num_data_lanes
61+
1250, // lane_bit_rate_mbps
62+
48, // dpi_clock_freq_mhz
63+
PixelFormat::Rgb888,
64+
);
65+
66+
// Create driver with DSI bus and DBI IO
67+
let mut lcd = LcdDriver::new(peripherals.dsi, &config)?;
68+
69+
// Create vendor control panel (e.g., ILI9881C) over DBI.
70+
//
71+
// Note: This requires the corresponding ESP-IDF component
72+
// (e.g., ILI9881C DSI panel driver) to be enabled.
73+
let mut dev_config: esp_lcd_panel_dev_config_t = lcd.config().into();
74+
75+
// Configure reset GPIO if your panel uses one (adjust as needed).
76+
// Use -1 for no reset GPIO.
77+
dev_config.reset_gpio_num = -1;
78+
79+
let mut control_panel: PanelHandle = core::ptr::null_mut();
80+
unsafe {
81+
// Replace `esp_lcd_new_panel_ili9881c` with the appropriate
82+
// vendor-specific constructor for your panel if needed.
83+
esp!(esp_lcd_new_panel_ili9881c(
84+
lcd.dbi_io_handle(),
85+
&dev_config,
86+
&mut control_panel
87+
))?;
88+
}
89+
lcd.set_control_panel(control_panel)?;
90+
91+
// Initialize the control panel
92+
lcd.reset()?;
93+
lcd.init()?;
94+
lcd.set_display_on(true)?;
95+
96+
// Create the DPI panel for pixel data transfers.
97+
// This consumes the NoDpiPanel driver and returns a WithDpiPanel driver.
98+
let lcd = lcd.create_dpi_panel()?;
99+
100+
// Simple test bitmap: clear screen to black.
101+
//
102+
// NOTE:
103+
// - draw_bitmap uses half-open intervals [x1, x2) × [y1, y2)
104+
// - For a 1024×600 display, use x2=1024, y2=600 (NOT 1023, 599)
105+
// - For RGB888, 3 bytes per pixel
106+
let bitmap = vec![0u8; 1024 * 600 * 3];
107+
108+
lcd.draw_bitmap(0, 0, 1024, 600, &bitmap)?;
109+
110+
// Keep the application alive so the display remains on
111+
loop {
112+
std::thread::sleep(Duration::from_secs(1));
113+
}
114+
}
115+
}
116+
117+
#[cfg(not(esp32p4))]
118+
mod example {
119+
pub fn run() -> anyhow::Result<()> {
120+
println!("This example is not supported on this target");
121+
Ok(())
122+
}
123+
}
124+
125+
fn main() -> anyhow::Result<()> {
126+
example::run()
127+
}

0 commit comments

Comments
 (0)