lcd_async/
_troubleshooting.rs

1//! # Troubleshooting guide
2//!
3//! This guide lists common issues that can cause a blank or corrupted display.
4//!
5//! ## Display stays black/blank
6//!
7//! ### Reset pin
8//!
9//! The reset pin on all supported display controllers is active low, requiring
10//! it to be driven **high** in order for the display to operate. It is
11//! recommended to connect the reset pin to a GPIO pin and let this crate
12//! control the pin by passing it to the builder via the `reset_pin` method. If
13//! this isn't possible in the target application the user must make sure that
14//! the reset pin on the display controller is kept in the high state before
15//! `init` is called.
16//!
17//! ### Backlight pin
18//!
19//! This driver does **NOT** handle the backlight pin to keep the code simpler.
20//! Users must control the backlight manually. First thing to try is to see if
21//! setting the backlight pin to high fixes the issue.
22//!
23//! ### Transport misconfiguration (e.g. SPI)
24//!
25//! Make sure that the transport layer is configured correctly. Typical mistakes
26//! are the use of wrong SPI MODE or too fast transfer speeds that are not
27//! supported by the display
28//!
29//! ## Incorrect colors
30//!
31//! The way colors are displayed depend on the subpixel layout and technology
32//! (like TN or IPS) used by the LCD panel. These physical parameters aren't
33//! known by the display controller and must be manually set by the user as
34//! `Builder` settings when the display is initialized.
35//!
36//! To make it easier to identify the correct settings the `lcd-async` crate
37//! provides a [`TestImage`](crate::TestImage), which can be used to verify the
38//! color settings and adjust them in case they are incorrect.
39//!
40//! ```
41//! use embedded_graphics::prelude::*;
42//! use embedded_graphics::pixelcolor::Rgb565;
43//! use lcd_async::{Builder, TestImage, models::ILI9341Rgb565, raw_framebuf::RawFrameBuf};
44//!
45//! # tokio_test::block_on(async {
46//! # let di = lcd_async::_mock::MockDisplayInterface;
47//! # let rst = lcd_async::_mock::MockOutputPin;
48//! # let mut delay = lcd_async::_mock::MockDelay;
49//! let mut display = Builder::new(ILI9341Rgb565, di)
50//!     .reset_pin(rst)
51//!     .init(&mut delay)
52//!     .await
53//!     .unwrap();
54//!
55//! // Create framebuffer for drawing
56//! const WIDTH: usize = 240;
57//! const HEIGHT: usize = 320;
58//! let mut buffer = [0u8; WIDTH * HEIGHT * 2]; // 2 bytes per pixel for RGB565
59//! let mut framebuf = RawFrameBuf::<Rgb565, _>::new(&mut buffer[..], WIDTH, HEIGHT);
60//!
61//! // Draw test image to framebuffer
62//! TestImage::new().draw(&mut framebuf)?;
63//!
64//! // IMPORTANT: After drawing to the framebuffer, you must send it to the display!
65//! // This is the key step that actually updates the screen.
66//! // display.show_raw_data(0, 0, WIDTH as u16, HEIGHT as u16, &buffer).await.unwrap();
67//!
68//! // For a complete working example, see: examples/spi-st7789-esp32-c3/src/main.rs
69//! # Ok::<(), core::convert::Infallible>(())
70//! # });
71//! ```
72//!
73//! The expected output from drawing the test image is:
74//!
75#![doc = include_str!("../docs/colors_correct.svg")]
76//!
77//! If the test image isn't displayed as expected use one of the reference image
78//! below the determine which settings need to be added to the
79//! [`Builder`](crate::Builder).
80//!
81//! ### Wrong subpixel order
82//!
83#![doc = include_str!("../docs/colors_wrong_subpixel_order.svg")]
84//!
85//! ```
86//! # use embedded_graphics::prelude::*;
87//! # use embedded_graphics::pixelcolor::Rgb565;
88//! # use lcd_async::{Builder, TestImage, models::ILI9341Rgb565, raw_framebuf::RawFrameBuf};
89//! #
90//! # tokio_test::block_on(async {
91//! # let di = lcd_async::_mock::MockDisplayInterface;
92//! # let mut delay = lcd_async::_mock::MockDelay;
93//! # let mut display = Builder::new(ILI9341Rgb565, di)
94//! .color_order(lcd_async::options::ColorOrder::Bgr)
95//! # .init(&mut delay).await.unwrap();
96//! # });
97//! ```
98//!
99//! ### Wrong color inversion
100//!
101#![doc = include_str!("../docs/colors_wrong_color_inversion.svg")]
102//!
103//! ```
104//! # use embedded_graphics::prelude::*;
105//! # use embedded_graphics::pixelcolor::Rgb565;
106//! # use lcd_async::{Builder, TestImage, models::ILI9341Rgb565, raw_framebuf::RawFrameBuf};
107//! #
108//! # tokio_test::block_on(async {
109//! # let di = lcd_async::_mock::MockDisplayInterface;
110//! # let mut delay = lcd_async::_mock::MockDelay;
111//! # let mut display = Builder::new(ILI9341Rgb565, di)
112//! .invert_colors(lcd_async::options::ColorInversion::Inverted)
113//! # .init(&mut delay).await.unwrap();
114//! # });
115//! ```
116//!
117//! ### Wrong subpixel order and color inversion
118//!
119#![doc = include_str!("../docs/colors_both_wrong.svg")]
120//!
121//! ```
122//! # use embedded_graphics::prelude::*;
123//! # use embedded_graphics::pixelcolor::Rgb565;
124//! # use lcd_async::{Builder, TestImage, models::ILI9341Rgb565, raw_framebuf::RawFrameBuf};
125//! #
126//! # tokio_test::block_on(async {
127//! # let di = lcd_async::_mock::MockDisplayInterface;
128//! # let mut delay = lcd_async::_mock::MockDelay;
129//! # let mut display = Builder::new(ILI9341Rgb565, di)
130//! .color_order(lcd_async::options::ColorOrder::Bgr)
131//! .invert_colors(lcd_async::options::ColorInversion::Inverted)
132//! # .init(&mut delay).await.unwrap();
133//! # });
134//! ```