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::{dcs_types::AddressMode, GenericMipidcs};
15
16pub mod consts;
17pub mod spec;
18
19use consts::*;
20pub use spec::Gc9a01Spec;
21
22pub struct Gc9a01<Spec, RST, B>
24where
25 Spec: Gc9a01Spec,
26 RST: OutputPin,
27 B: DisplayBus,
28{
29 inner: GenericMipidcs<B, Spec, RST>,
31}
32
33impl<Spec, RST, B> Gc9a01<Spec, RST, B>
34where
35 Spec: Gc9a01Spec,
36 RST: OutputPin,
37 B: DisplayBus,
38{
39 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 const INIT_STEPS: &'static [InitStep<'static>] = &[
67 InitStep::CommandWithParams(INTER_REGISTER_ENABLE_2, &[]), InitStep::CommandWithParams(0xEB, &[0x14]),
69 InitStep::CommandWithParams(INTER_REGISTER_ENABLE_1, &[]), InitStep::CommandWithParams(INTER_REGISTER_ENABLE_2, &[]), InitStep::CommandWithParams(0xEB, &[0x14]),
73 InitStep::CommandWithParams(0x84, &[0x40]),
74 InitStep::CommandWithParams(0x85, &[0xFF]),
75 InitStep::CommandWithParams(0x86, &[0xFF]),
76 InitStep::CommandWithParams(0x87, &[0xFF]),
77 InitStep::CommandWithParams(0x88, &[0x0A]),
78 InitStep::CommandWithParams(0x89, &[0x21]),
79 InitStep::CommandWithParams(0x8A, &[0x00]),
80 InitStep::CommandWithParams(0x8B, &[0x80]),
81 InitStep::CommandWithParams(0x8C, &[0x01]),
82 InitStep::CommandWithParams(0x8D, &[0x01]),
83 InitStep::CommandWithParams(0x8E, &[0xFF]),
84 InitStep::CommandWithParams(0x8F, &[0xFF]),
85 InitStep::CommandWithParams(DISPLAY_FUNCTION_CONTROL, &[0x00, 0x20]), InitStep::select_cmd(
88 Spec::INVERTED,
89 mipidcs::ENTER_INVERT_MODE,
90 mipidcs::EXIT_INVERT_MODE,
91 ),
92 InitStep::CommandWithParams(
93 mipidcs::SET_ADDRESS_MODE,
94 &[if Spec::BGR {
95 AddressMode::BGR.bits()
96 } else {
97 0u8
98 }],
99 ),
100 InitStep::CommandWithParams(mipidcs::SET_PIXEL_FORMAT, &[0x05]), InitStep::CommandWithParams(0x90, &[0x08, 0x08, 0x08, 0x08]),
103 InitStep::CommandWithParams(0xBD, &[0x06]),
104 InitStep::CommandWithParams(0xBC, &[0x00]),
105 InitStep::CommandWithParams(0xFF, &[0x60, 0x01, 0x04]),
106 InitStep::CommandWithParams(POWER_CONTROL_2, &[0x13]), InitStep::CommandWithParams(POWER_CONTROL_3, &[0x13]), InitStep::CommandWithParams(POWER_CONTROL_4, &[0x22]), InitStep::CommandWithParams(0xBE, &[0x11]),
111 InitStep::CommandWithParams(0xE1, &[0x10, 0x0E]),
112 InitStep::CommandWithParams(0xDF, &[0x21, 0x0C, 0x02]),
113 InitStep::CommandWithParams(SET_GAMMA_1, &[0x45, 0x09, 0x08, 0x08, 0x26, 0x2A]),
115 InitStep::CommandWithParams(SET_GAMMA_2, &[0x43, 0x70, 0x72, 0x36, 0x37, 0x6F]),
116 InitStep::CommandWithParams(SET_GAMMA_3, &[0x45, 0x09, 0x08, 0x08, 0x26, 0x2A]),
117 InitStep::CommandWithParams(SET_GAMMA_4, &[0x43, 0x70, 0x72, 0x36, 0x37, 0x6F]),
118 InitStep::CommandWithParams(0xED, &[0x1B, 0x0B]),
119 InitStep::CommandWithParams(0xAE, &[0x77]),
120 InitStep::CommandWithParams(0xCD, &[0x63]),
121 InitStep::CommandWithParams(FRAME_RATE_CONTROL, &[0x34]),
126 InitStep::CommandWithParams(
127 0x62,
128 &[
129 0x18, 0x0D, 0x71, 0xED, 0x70, 0x70, 0x18, 0x0F, 0x71, 0xEF, 0x70, 0x70,
130 ],
131 ),
132 InitStep::CommandWithParams(
133 0x63,
134 &[
135 0x18, 0x11, 0x71, 0xF1, 0x70, 0x70, 0x18, 0x13, 0x71, 0xF3, 0x70, 0x70,
136 ],
137 ),
138 InitStep::CommandWithParams(0x64, &[0x28, 0x29, 0xF1, 0x01, 0xF1, 0x00, 0x07]),
139 InitStep::CommandWithParams(
140 0x66,
141 &[0x3C, 0x00, 0xCD, 0x67, 0x45, 0x45, 0x10, 0x00, 0x00, 0x00],
142 ),
143 InitStep::CommandWithParams(
144 0x67,
145 &[0x00, 0x3C, 0x00, 0x00, 0x00, 0x01, 0x54, 0x10, 0x32, 0x98],
146 ),
147 InitStep::CommandWithParams(0x74, &[0x10, 0x85, 0x80, 0x00, 0x00, 0x4E, 0x00]),
148 InitStep::CommandWithParams(0x98, &[0x3E, 0x07]),
149 InitStep::SingleCommand(mipidcs::SET_TEAR_OFF),
150 InitStep::SingleCommand(mipidcs::ENTER_INVERT_MODE), InitStep::SingleCommand(mipidcs::EXIT_SLEEP_MODE), InitStep::DelayMs(120),
154 InitStep::SingleCommand(mipidcs::SET_DISPLAY_ON),
155 InitStep::DelayMs(20),
156 ];
157}
158
159impl<Spec, RST, B> Panel<B> for Gc9a01<Spec, RST, B>
160where
161 Spec: Gc9a01Spec,
162 RST: OutputPin,
163 B: DisplayBus,
164{
165 const CMD_LEN: usize = 1;
166 const PIXEL_WRITE_CMD: [u8; 4] = [mipidcs::WRITE_MEMORY_START, 0, 0, 0];
167
168 async fn init<D: DelayNs>(&mut self, bus: &mut B, mut delay: D) -> Result<(), B::Error> {
169 let mut reseter = LCDResetHandler::new(
171 &mut self.inner.reset_pin,
172 bus,
173 &mut delay,
174 10,
175 120,
176 Some(&[mipidcs::SOFT_RESET]),
177 );
178 reseter.reset().await?;
179
180 self.inner.address_mode.set(AddressMode::BGR, Spec::BGR);
182
183 sequenced_init(Self::INIT_STEPS.iter().copied(), &mut delay, bus).await
186 }
187
188 delegate::delegate! {
189 to self.inner {
190 fn width(&self) -> u16;
191
192 fn height(&self) -> u16;
193
194 fn size(&self) -> (u16, u16);
195
196 async fn set_window(
197 &mut self,
198 bus: &mut B,
199 x0: u16,
200 y0: u16,
201 x1: u16,
202 y1: u16,
203 ) -> Result<(), DisplayError<B::Error>>;
204
205 async fn set_color_format(
206 &mut self,
207 bus: &mut B,
208 color_format: ColorFormat,
209 ) -> Result<(), DisplayError<B::Error>>;
210
211 async fn set_orientation(
212 &mut self,
213 bus: &mut B,
214 orientation: Orientation,
215 ) -> Result<(), DisplayError<B::Error>>;
216 }
217 }
218}
219
220impl<Spec, RST, B> PanelSetBrightness<B> for Gc9a01<Spec, RST, B>
221where
222 Spec: Gc9a01Spec,
223 RST: OutputPin,
224 B: DisplayBus,
225{
226 async fn set_brightness(
227 &mut self,
228 bus: &mut B,
229 brightness: u8,
230 ) -> Result<(), DisplayError<B::Error>> {
231 bus.write_cmd_with_params(&[WRITE_DISPLAY_BRIGHTNESS], &[brightness])
232 .await
233 .map_err(DisplayError::BusError)
234 }
235}