Skip to main content

display_driver_co5300/
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::{LCDResetOption, LCDResetHandler};
9use display_driver::panel::{Orientation, Panel, PanelSetBrightness};
10
11use display_driver::{ColorFormat, DisplayError};
12
13// Use GenericMipidcs to handle standard DCS operations
14use display_driver_mipidcs::{consts::*, dcs_types::AddressMode, GenericMipidcs};
15
16pub mod consts;
17pub mod spec;
18
19use consts::*;
20use spec::Co5300Spec;
21
22/// Driver for the CO5300 AMOLED display controller.
23pub struct Co5300<Spec, RST, B>
24where
25    Spec: Co5300Spec,
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> Co5300<Spec, RST, B>
34where
35    Spec: Co5300Spec,
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    /// Sets the display brightness (0-255).
47    pub async fn set_brightness(
48        &mut self,
49        bus: &mut B,
50        value: u8,
51    ) -> Result<(), DisplayError<B::Error>> {
52        bus.write_cmd_with_params(&[WBRIGHT], &[value])
53            .await
54            .map_err(DisplayError::BusError)
55    }
56
57    delegate::delegate! {
58        to self.inner {
59            pub async fn set_invert_mode(
60                &mut self,
61                bus: &mut B,
62                invert: bool,
63            ) -> Result<(), B::Error>;
64
65            pub async fn set_address_mode(
66                &mut self,
67                bus: &mut B,
68                address_mode: AddressMode,
69                orientation_if_changed: Option<Orientation>,
70            ) -> Result<(), B::Error>;
71
72            pub async fn set_bgr_order(&mut self, bus: &mut B, bgr: bool) -> Result<(), B::Error>;
73        }
74    }
75
76    /// Initialization sequence for CO5300.
77    const INIT_STEPS: &'static [InitStep<'static>] = &[
78        // Unlock Sequence
79        InitStep::CommandWithParams(CMD_PAGE_SWITCH, &[Spec::INIT_PAGE_PARAM]),
80        InitStep::CommandWithParams(PASSWD1, &[0x5A]),
81        InitStep::CommandWithParams(PASSWD2, &[0x59]),
82        // Lock Sequence
83        InitStep::CommandWithParams(CMD_PAGE_SWITCH, &[0x20]),
84        InitStep::CommandWithParams(PASSWD1, &[0xA5]),
85        InitStep::CommandWithParams(PASSWD2, &[0xA5]),
86        // Configuration
87        InitStep::CommandWithParams(CMD_PAGE_SWITCH, &[0x00]),
88        InitStep::CommandWithParams(SPI_MODE, &[0x80]),
89        InitStep::CommandWithParams(COLOR_MODE, &[0x55]), // Default to RGB565
90        InitStep::CommandWithParams(TEARING_EFFECT_ON, &[0x00]),
91        InitStep::CommandWithParams(WRITE_CTRL_DISPLAY, &[0x20]),
92        InitStep::CommandWithParams(WRHBMDISBV, &[0xFF]),
93        // Power On
94        InitStep::SingleCommand(SLEEP_OUT),
95        InitStep::DelayMs(120),
96        InitStep::SingleCommand(DISPLAY_ON),
97        InitStep::DelayMs(70),
98    ];
99}
100
101impl<Spec, RST, B> Panel<B> for Co5300<Spec, RST, B>
102where
103    Spec: Co5300Spec,
104    RST: OutputPin,
105    B: DisplayBus,
106{
107    const CMD_LEN: usize = 1;
108    const PIXEL_WRITE_CMD: [u8; 4] = [WRITE_RAM, 0, 0, 0];
109
110    fn x_alignment(&self) -> u16 {
111        2
112    }
113
114    fn y_alignment(&self) -> u16 {
115        2
116    }
117
118    async fn init<D: DelayNs>(&mut self, bus: &mut B, mut delay: D) -> Result<(), B::Error> {
119        let mut reseter = LCDResetHandler::new(
120            &mut self.inner.reset_pin,
121            bus,
122            &mut delay,
123            10,
124            120,
125            Some(&[SOFT_RESET]),
126        );
127        reseter.reset().await?;
128
129        // Execute Initialization Sequence
130        // copied() only copies the items during iteration; it does not copy the entire sequence
131        sequenced_init(Self::INIT_STEPS.iter().copied(), &mut delay, bus).await
132    }
133
134    delegate::delegate! {
135        to self.inner {
136            fn width(&self) -> u16;
137
138            fn height(&self) -> u16;
139
140            fn size(&self) -> (u16, u16);
141
142            async fn set_window(
143                &mut self,
144                bus: &mut B,
145                x0: u16,
146                y0: u16,
147                x1: u16,
148                y1: u16,
149            ) -> Result<(), DisplayError<B::Error>>;
150
151            async fn set_color_format(
152                &mut self,
153                bus: &mut B,
154                color_format: ColorFormat,
155            ) -> Result<(), DisplayError<B::Error>>;
156
157            async fn set_orientation(
158                &mut self,
159                bus: &mut B,
160                orientation: Orientation,
161            ) -> Result<(), DisplayError<B::Error>>;
162        }
163    }
164}
165
166impl<Spec, RST, B> PanelSetBrightness<B> for Co5300<Spec, RST, B>
167where
168    Spec: Co5300Spec,
169    RST: OutputPin,
170    B: DisplayBus,
171{
172    async fn set_brightness(
173        &mut self,
174        bus: &mut B,
175        brightness: u8,
176    ) -> Result<(), DisplayError<B::Error>> {
177        bus.write_cmd_with_params(&[WBRIGHT], &[brightness])
178            .await
179            .map_err(DisplayError::BusError)
180    }
181}