Skip to main content

display_driver_st7789/
lib.rs

1#![no_std]
2
3use embedded_hal::digital::OutputPin;
4use embedded_hal_async::delay::DelayNs;
5
6use display_driver::bus::DisplayBus;
7use display_driver::panel::initseq::{sequenced_init, InitStep};
8use display_driver::panel::reset::{LCDResetHandler, LCDResetOption};
9use display_driver::panel::{Orientation, Panel, PanelSetBrightness};
10
11use display_driver::{ColorFormat, DisplayError};
12
13use display_driver_mipidcs as mipidcs;
14use display_driver_mipidcs::{AddressMode, GenericMipidcs};
15
16pub mod consts;
17pub mod spec;
18
19use consts::*;
20pub use spec::St7789Spec;
21
22/// Driver for the ST7789 display controller.
23pub struct St7789<Spec, RST, B>
24where
25    Spec: St7789Spec,
26    RST: OutputPin,
27    B: DisplayBus,
28{
29    /// Inner generic driver for standard functionality.
30    inner: GenericMipidcs<B, Spec, RST>,
31}
32
33impl<Spec, RST, B> St7789<Spec, RST, B>
34where
35    Spec: St7789Spec,
36    RST: OutputPin,
37    B: DisplayBus,
38{
39    /// Creates a new driver instance.
40    pub fn new(reset_pin: LCDResetOption<RST>) -> Self {
41        Self {
42            inner: GenericMipidcs::new(reset_pin),
43        }
44    }
45
46    delegate::delegate! {
47        to self.inner {
48            pub async fn set_invert_mode(
49                &mut self,
50                bus: &mut B,
51                invert: bool,
52            ) -> Result<(), B::Error>;
53
54            pub async fn set_address_mode(
55                &mut self,
56                bus: &mut B,
57                address_mode: AddressMode,
58                orientation_if_changed: Option<Orientation>,
59            ) -> Result<(), B::Error>;
60
61            pub async fn set_bgr_order(&mut self, bus: &mut B, bgr: bool) -> Result<(), B::Error>;
62        }
63    }
64
65    /// Initialization sequence for ST7789.
66    const INIT_STEPS: &'static [InitStep<'static>] = &[
67        // Sleep Out
68        InitStep::SingleCommand(mipidcs::EXIT_SLEEP_MODE),
69        InitStep::DelayMs(120),
70        // Interface Pixel Format
71        InitStep::CommandWithParams(
72            mipidcs::SET_PIXEL_FORMAT,
73            &mipidcs::PixelFormat::dbi_and_dpi(mipidcs::PixelFormatType::Bits16).as_bytes(),
74        ),
75        // Porch Setting
76        InitStep::CommandWithParams(PORCTRL, &Spec::PORCTRL_PARAMS),
77        // Gate Control
78        InitStep::CommandWithParams(GCTRL, &[Spec::GCTRL_PARAM]),
79        // VCOM Setting
80        InitStep::CommandWithParams(VCOMS, &[Spec::VCOMS_PARAM]),
81        // LCM Control
82        InitStep::CommandWithParams(LCMCTRL, &[Spec::LCMCTRL_PARAM]),
83        // VDV and VRH Command Enable
84        InitStep::CommandWithParams(VDVVRHEN, &[0x01, 0xFF]),
85        // VRH Set
86        InitStep::CommandWithParams(VRHS, &[Spec::VRHS_PARAM]),
87        // VDV Set
88        InitStep::CommandWithParams(VDVS, &[Spec::VDVS_PARAM]),
89        // Frame Rate Control
90        InitStep::CommandWithParams(FRCTRL2, &[Spec::FRCTRL2_PARAM]),
91        // Power Control 1
92        InitStep::CommandWithParams(PWCTRL1, &Spec::PWCTRL1_PARAMS),
93        // Power Control 2 (Optional)
94        InitStep::maybe_cmd_with(PWCTRL2, Spec::PWCTRL2_PARAMS),
95        // Equalize time control (Optional)
96        InitStep::maybe_cmd_with(EQCTRL, Spec::EQCTRL_PARAMS),
97        // Gate Output Selection (Optional)
98        InitStep::maybe_cmd_with(GATESEL, Spec::GATESEL_PARAMS),
99        // Gamma
100        InitStep::CommandWithParams(PVGAMCTRL, &Spec::PVGAMCTRL_PARAMS),
101        InitStep::CommandWithParams(NVGAMCTRL, &Spec::NVGAMCTRL_PARAMS),
102        // Invert Mode
103        InitStep::select_cmd(
104            Spec::INVERTED,
105            mipidcs::ENTER_INVERT_MODE,
106            mipidcs::EXIT_INVERT_MODE,
107        ),
108        InitStep::CommandWithParams(
109            mipidcs::SET_ADDRESS_MODE,
110            &[if Spec::BGR {
111                AddressMode::BGR.bits()
112            } else {
113                0u8
114            }],
115        ),
116        // Display On
117        InitStep::SingleCommand(mipidcs::SET_DISPLAY_ON),
118        InitStep::DelayMs(120),
119    ];
120}
121
122impl<Spec, RST, B> Panel<B> for St7789<Spec, RST, B>
123where
124    Spec: St7789Spec,
125    RST: OutputPin,
126    B: DisplayBus,
127{
128    const CMD_LEN: usize = 1;
129    const PIXEL_WRITE_CMD: [u8; 4] = [mipidcs::WRITE_MEMORY_START, 0, 0, 0];
130
131    async fn init<D: DelayNs>(&mut self, bus: &mut B, mut delay: D) -> Result<(), B::Error> {
132        // Hardware Reset
133        let mut reseter = LCDResetHandler::new(
134            &mut self.inner.reset_pin,
135            bus,
136            &mut delay,
137            10,
138            120,
139            Some(&[mipidcs::SOFT_RESET]),
140        );
141        reseter.reset().await?;
142
143        // Initialize address mode state
144        self.inner.address_mode.set(AddressMode::BGR, Spec::BGR);
145
146        // Execute Initialization Sequence
147        // copied() only copies the items during iteration; it does not copy the entire sequence
148        sequenced_init(Self::INIT_STEPS.iter().copied(), &mut delay, bus).await
149    }
150
151    delegate::delegate! {
152        to self.inner {
153            fn width(&self) -> u16;
154
155            fn height(&self) -> u16;
156
157            fn size(&self) -> (u16, u16);
158
159            async fn set_window(
160                &mut self,
161                bus: &mut B,
162                x0: u16,
163                y0: u16,
164                x1: u16,
165                y1: u16,
166            ) -> Result<(), DisplayError<B::Error>>;
167
168            async fn set_color_format(
169                &mut self,
170                bus: &mut B,
171                color_format: ColorFormat,
172            ) -> Result<(), DisplayError<B::Error>>;
173
174            async fn set_orientation(
175                &mut self,
176                bus: &mut B,
177                orientation: Orientation,
178            ) -> Result<(), DisplayError<B::Error>>;
179        }
180    }
181}
182
183impl<Spec, RST, B> PanelSetBrightness<B> for St7789<Spec, RST, B>
184where
185    Spec: St7789Spec,
186    RST: OutputPin,
187    B: DisplayBus,
188{
189    async fn set_brightness(
190        &mut self,
191        bus: &mut B,
192        brightness: u8,
193    ) -> Result<(), DisplayError<B::Error>> {
194        bus.write_cmd_with_params(&[WRDISBV], &[brightness])
195            .await
196            .map_err(DisplayError::BusError)
197    }
198}