-
Notifications
You must be signed in to change notification settings - Fork 211
Initial LCD support. #568
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Initial LCD support. #568
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,124 @@ | ||
| //! Basic LCD DSI example for ESP32-P4 | ||
| //! | ||
| //! This example shows how to: | ||
| //! - Configure the LCD peripheral for a DSI panel | ||
| //! - Create a vendor-specific control panel (ILI9881C over DBI) | ||
| //! - Initialize the panel | ||
| //! - Create a DPI panel for frame updates | ||
| //! - Draw a simple framebuffer | ||
| //! | ||
| //! Requirements: | ||
| //! - Target: ESP32-P4 (`ESP_IDF_TARGET=esp32p4`) | ||
| //! - ESP-IDF must have the ILI9881C DSI panel component enabled | ||
| //! - A compatible 1024×600 MIPI-DSI display connected to the LCD peripheral | ||
| #![allow(unknown_lints)] | ||
| #![allow(unexpected_cfgs)] | ||
|
|
||
| #[cfg(esp32p4)] | ||
| mod example { | ||
| use std::time::Duration; | ||
|
|
||
| use esp_idf_hal::lcd::*; | ||
| use esp_idf_hal::ldo::*; | ||
| use esp_idf_hal::peripherals::Peripherals; | ||
|
|
||
| use esp_idf_sys::*; | ||
|
|
||
| pub fn run() -> anyhow::Result<()> { | ||
| // Link ESP-IDF patches (required for examples) | ||
| esp_idf_hal::sys::link_patches(); | ||
|
|
||
| let peripherals = Peripherals::take()?; | ||
|
|
||
| // Configure LDO3 for MIPI D-PHY supply (typically 2.5 V). | ||
| // | ||
| // NOTE: Adjust the voltage to match your board's design and panel | ||
| // requirements. 2.5 V is a common value for the DSI PHY supply. | ||
| let ldo_cfg = LdoChannelConfig::new(2500); | ||
| let _ldo3 = LdoChannel::new(&peripherals.ldo3, &ldo_cfg)?; | ||
|
|
||
| // Give the LDO some time to stabilize before enabling the panel. | ||
| std::thread::sleep(Duration::from_millis(20)); | ||
|
|
||
| // Configure video timing for a 1024×600 panel. | ||
| // Adjust these values to match your panel's datasheet. | ||
| let video_timing = VideoTiming::new(1024, 600) | ||
| .hsync_back_porch(100) | ||
| .hsync_pulse_width(100) | ||
| .hsync_front_porch(100) | ||
| .vsync_back_porch(10) | ||
| .vsync_pulse_width(10) | ||
| .vsync_front_porch(10); | ||
|
|
||
| // High-level LCD configuration: | ||
| // - 2 DSI data lanes at 1250 Mbps | ||
| // - RGB888 pixel format | ||
| // - DPI clock at 48 MHz | ||
| let config = LcdConfig::new(video_timing) | ||
| .num_data_lanes(2) | ||
| .lane_bit_rate_mbps(1250) | ||
| .dpi_clock_freq_mhz(48) | ||
| .pixel_format(PixelFormat::Rgb888); | ||
|
|
||
| // Create driver with DSI bus and DBI IO | ||
| let mut lcd = LcdDriver::new(peripherals.lcd, &config)?; | ||
|
|
||
| // Create vendor control panel (e.g., ILI9881C) over DBI. | ||
| // | ||
| // Note: This requires the corresponding ESP-IDF component | ||
| // (e.g., ILI9881C DSI panel driver) to be enabled. | ||
| let mut dev_config: esp_lcd_panel_dev_config_t = lcd.config().into(); | ||
|
|
||
| // Configure reset GPIO if your panel uses one (adjust as needed). | ||
| // Use -1 for no reset GPIO. | ||
| dev_config.reset_gpio_num = -1; | ||
|
|
||
| let mut control_panel: esp_lcd_panel_handle_t = core::ptr::null_mut(); | ||
| unsafe { | ||
| // Replace `esp_lcd_new_panel_ili9881c` with the appropriate | ||
| // vendor-specific constructor for your panel if needed. | ||
| esp!(esp_lcd_new_panel_ili9881c( | ||
| lcd.dbi_io_handle(), | ||
| &dev_config, | ||
| &mut control_panel | ||
| ))?; | ||
| } | ||
| lcd.set_control_panel(control_panel)?; | ||
|
|
||
| // Initialize the control panel | ||
| lcd.reset()?; | ||
| lcd.init()?; | ||
| lcd.set_display_on(true)?; | ||
|
|
||
| // Create the DPI panel for pixel data transfers | ||
| lcd.create_dpi_panel()?; | ||
|
|
||
| // Simple test framebuffer: clear screen to black. | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think it is fair to call the bitmap you use here a "framebuffer". A "framebuffer" is something else: in drivers that do support/need framebuffers, this is a region of memory, where a simple write of one or more bytes gets immediately (or almost immediately) reflected on the actual screen. In fact, one of my biggest concerns below is regarding the usage of a hidden (large) framebuffer by the LCD driver itself. |
||
| // | ||
| // NOTE: | ||
| // - draw_bitmap uses half-open intervals [x1, x2) × [y1, y2) | ||
| // - For a 1024×600 display, use x2=1024, y2=600 (NOT 1023, 599) | ||
| // - For RGB888, 3 bytes per pixel | ||
| let framebuffer = vec![0u8; 1024 * 600 * 3]; | ||
|
|
||
| lcd.draw_bitmap(0, 0, 1024, 600, &framebuffer)?; | ||
|
|
||
| // Keep the application alive so the display remains on | ||
| loop { | ||
| std::thread::sleep(Duration::from_secs(1)); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| #[cfg(not(esp32p4))] | ||
| mod example { | ||
| pub fn run() -> anyhow::Result<()> { | ||
| println!("This example is not supported on this target"); | ||
| Ok(()) | ||
| } | ||
| } | ||
|
|
||
| fn main() -> anyhow::Result<()> { | ||
| example::run() | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps: