weact_studio_epd/
driver.rs

1use core::iter;
2
3#[cfg(not(feature = "blocking"))]
4use display_interface::AsyncWriteOnlyDataCommand;
5#[cfg(feature = "blocking")]
6use display_interface::WriteOnlyDataCommand;
7
8#[cfg(feature = "blocking")]
9use embedded_hal::delay::DelayNs;
10#[cfg(not(feature = "blocking"))]
11use embedded_hal_async::{delay::DelayNs, digital::Wait};
12
13use display_interface::DataFormat;
14use embedded_hal::digital::{InputPin, OutputPin};
15
16#[cfg(feature = "graphics")]
17use crate::graphics::Display;
18use crate::{
19    color::{self, ColorType},
20    command, flag, lut, Color, Result, TriColor,
21};
22
23/// Display driver for the WeAct Studio 2.9 inch B/W display.
24pub type WeActStudio290BlackWhiteDriver<DI, BSY, RST, DELAY> =
25    DisplayDriver<DI, BSY, RST, DELAY, 128, 128, 296, Color>;
26/// Display driver for the WeAct Studio 2.9 inch Tri-Color display.
27pub type WeActStudio290TriColorDriver<DI, BSY, RST, DELAY> =
28    DisplayDriver<DI, BSY, RST, DELAY, 128, 128, 296, TriColor>;
29/// Display driver for the WeAct Studio 2.13 inch B/W display.
30pub type WeActStudio213BlackWhiteDriver<DI, BSY, RST, DELAY> =
31    DisplayDriver<DI, BSY, RST, DELAY, 128, 122, 250, Color>;
32/// Display driver for the WeAct Studio 2.13 inch Tri-Color display.
33pub type WeActStudio213TriColorDriver<DI, BSY, RST, DELAY> =
34    DisplayDriver<DI, BSY, RST, DELAY, 128, 122, 250, TriColor>;
35
36/// The main driver struct that manages the communication with the display.
37///
38/// You probably want to use one of the display-specific type aliases instead.
39pub struct DisplayDriver<
40    DI,
41    BSY,
42    RST,
43    DELAY,
44    const WIDTH: u32,
45    const VISIBLE_WIDTH: u32,
46    const HEIGHT: u32,
47    C,
48> {
49    _color: core::marker::PhantomData<C>,
50    interface: DI,
51    busy: BSY,
52    reset: RST,
53    delay: DELAY,
54    // State
55    using_partial_mode: bool,
56    initial_full_refresh_done: bool,
57}
58
59#[maybe_async_cfg::maybe(
60    sync(
61        feature = "blocking",
62        keep_self,
63        idents(
64            AsyncWriteOnlyDataCommand(sync = "WriteOnlyDataCommand"),
65            Wait(sync = "InputPin")
66        )
67    ),
68    async(not(feature = "blocking"), keep_self)
69)]
70impl<DI, BSY, RST, DELAY, const WIDTH: u32, const VISIBLE_WIDTH: u32, const HEIGHT: u32, C>
71    DisplayDriver<DI, BSY, RST, DELAY, WIDTH, VISIBLE_WIDTH, HEIGHT, C>
72where
73    DI: AsyncWriteOnlyDataCommand,
74    BSY: InputPin + Wait,
75    RST: OutputPin,
76    DELAY: DelayNs,
77    C: ColorType,
78{
79    const RESET_DELAY_MS: u32 = 50;
80
81    /// Create a new display driver.
82    ///
83    /// Use [`Self::init`] to initialize the display.
84    pub fn new(interface: DI, busy: BSY, reset: RST, delay: DELAY) -> Self {
85        Self {
86            _color: core::marker::PhantomData,
87            interface,
88            busy,
89            reset,
90            delay,
91            using_partial_mode: false,
92            initial_full_refresh_done: false,
93        }
94    }
95
96    /// Initialize the display
97    pub async fn init(&mut self) -> Result<()> {
98        self.hw_reset().await;
99        self.command(command::SW_RESET).await?;
100        self.delay.delay_ms(10).await;
101        self.wait_until_idle().await;
102        self.command_with_data(
103            command::DRIVER_CONTROL,
104            &[(HEIGHT - 1) as u8, ((HEIGHT - 1) >> 8) as u8, 0x00],
105        )
106        .await?;
107        self.command_with_data(command::DATA_ENTRY_MODE, &[flag::DATA_ENTRY_INCRY_INCRX])
108            .await?;
109        self.command_with_data(
110            command::BORDER_WAVEFORM_CONTROL,
111            &[flag::BORDER_WAVEFORM_FOLLOW_LUT | flag::BORDER_WAVEFORM_LUT1],
112        )
113        .await?;
114        self.command_with_data(command::DISPLAY_UPDATE_CONTROL, &[0x00, 0x80])
115            .await?;
116        self.command_with_data(command::TEMP_CONTROL, &[flag::INTERNAL_TEMP_SENSOR])
117            .await?;
118        self.use_full_frame().await?;
119        self.wait_until_idle().await;
120        Ok(())
121    }
122
123    /// Perform a hardware reset of the display.
124    pub async fn hw_reset(&mut self) {
125        self.reset.set_low().unwrap();
126        self.delay.delay_ms(Self::RESET_DELAY_MS).await;
127        self.reset.set_high().unwrap();
128        self.delay.delay_ms(Self::RESET_DELAY_MS).await;
129    }
130
131    /// Write to the B/W buffer.
132    pub async fn write_bw_buffer(&mut self, buffer: &[u8]) -> Result<()> {
133        self.use_full_frame().await?;
134        self.command_with_data(command::WRITE_BW_DATA, buffer)
135            .await?;
136        Ok(())
137    }
138
139    /// Write to the red buffer.
140    ///
141    /// On B/W displays this buffer is used for fast refreshes.
142    pub async fn write_red_buffer(&mut self, buffer: &[u8]) -> Result<()> {
143        self.use_full_frame().await?;
144        self.command_with_data(command::WRITE_RED_DATA, buffer)
145            .await?;
146        Ok(())
147    }
148
149    /// Write to the B/W buffer at the given position.
150    ///
151    /// `x`, and `width` must be multiples of 8.
152    pub async fn write_partial_bw_buffer(
153        &mut self,
154        buffer: &[u8],
155        x: u32,
156        y: u32,
157        width: u32,
158        height: u32,
159    ) -> Result<()> {
160        self.use_partial_frame(x, y, width, height).await?;
161        self.command_with_data(command::WRITE_BW_DATA, buffer)
162            .await?;
163        Ok(())
164    }
165
166    /// Write to the red buffer at the given position.
167    ///
168    /// `x`, and `width` must be multiples of 8.
169    ///
170    /// On B/W displays this buffer is used for fast refreshes.
171    pub async fn write_partial_red_buffer(
172        &mut self,
173        buffer: &[u8],
174        x: u32,
175        y: u32,
176        width: u32,
177        height: u32,
178    ) -> Result<()> {
179        self.use_partial_frame(x, y, width, height).await?;
180        self.command_with_data(command::WRITE_RED_DATA, buffer)
181            .await?;
182        Ok(())
183    }
184
185    /// Make the whole black and white frame on the display driver white.
186    pub async fn clear_bw_buffer(&mut self) -> Result<()> {
187        self.use_full_frame().await?;
188
189        // TODO: allow non-white background color
190        let color = color::Color::White.byte_value().0;
191
192        self.command(command::WRITE_BW_DATA).await?;
193        self.data_x_times(color, WIDTH / 8 * HEIGHT).await?;
194        Ok(())
195    }
196
197    /// Make the whole red frame on the display driver white.
198    ///
199    /// On B/W displays this buffer is used for fast refreshes.
200    pub async fn clear_red_buffer(&mut self) -> Result<()> {
201        self.use_full_frame().await?;
202
203        // TODO: allow non-white background color
204        let color = color::Color::White.byte_value().1;
205
206        self.command(command::WRITE_RED_DATA).await?;
207        self.data_x_times(color, WIDTH / 8 * HEIGHT).await?;
208        Ok(())
209    }
210
211    /// Start a full refresh of the display.
212    pub async fn full_refresh(&mut self) -> Result<()> {
213        self.initial_full_refresh_done = true;
214        self.using_partial_mode = false;
215
216        self.command_with_data(command::UPDATE_DISPLAY_CTRL2, &[flag::DISPLAY_MODE_1])
217            .await?;
218        self.command(command::MASTER_ACTIVATE).await?;
219        self.wait_until_idle().await;
220        Ok(())
221    }
222
223    /// Put the device into deep-sleep mode.
224    /// You will need to call [`Self::wake_up`] before you can draw to the screen again.
225    pub async fn sleep(&mut self) -> Result<()> {
226        // We can't use send_with_data, because the data function will also wait_until_idle,
227        // but after sending the deep sleep command, busy will not be cleared,
228        // maybe as a feature to signal the device won't be able to process further instuctions until woken again.
229        self.interface
230            .send_commands(DataFormat::U8(&[command::DEEP_SLEEP]))
231            .await?;
232        self.interface
233            .send_data(DataFormat::U8(&[flag::DEEP_SLEEP_MODE_1]))
234            .await?;
235        Ok(())
236    }
237
238    /// Wake the device up from deep-sleep mode.
239    pub async fn wake_up(&mut self) -> Result<()> {
240        // HW reset seems to be enough in deep sleep mode 1, no need to call init again
241        self.hw_reset().await;
242        Ok(())
243    }
244
245    async fn use_full_frame(&mut self) -> Result<()> {
246        self.use_partial_frame(0, 0, WIDTH, HEIGHT).await?;
247        Ok(())
248    }
249
250    async fn use_partial_frame(&mut self, x: u32, y: u32, width: u32, height: u32) -> Result<()> {
251        // TODO: make sure positions are byte-aligned
252        self.set_ram_area(x, y, x + width - 1, y + height - 1)
253            .await?;
254        self.set_ram_counter(x, y).await?;
255        Ok(())
256    }
257
258    async fn set_ram_area(
259        &mut self,
260        start_x: u32,
261        start_y: u32,
262        end_x: u32,
263        end_y: u32,
264    ) -> Result<()> {
265        assert!(start_x < end_x);
266        assert!(start_y < end_y);
267
268        self.command_with_data(
269            command::SET_RAMXPOS,
270            &[(start_x >> 3) as u8, (end_x >> 3) as u8],
271        )
272        .await?;
273
274        self.command_with_data(
275            command::SET_RAMYPOS,
276            &[
277                start_y as u8,
278                (start_y >> 8) as u8,
279                end_y as u8,
280                (end_y >> 8) as u8,
281            ],
282        )
283        .await?;
284        Ok(())
285    }
286
287    async fn set_ram_counter(&mut self, x: u32, y: u32) -> Result<()> {
288        // x is positioned in bytes, so the last 3 bits which show the position inside a byte in the ram
289        // aren't relevant
290        self.command_with_data(command::SET_RAMX_COUNTER, &[(x >> 3) as u8])
291            .await?;
292
293        // 2 Databytes: A[7:0] & 0..A[8]
294        self.command_with_data(command::SET_RAMY_COUNTER, &[y as u8, (y >> 8) as u8])
295            .await?;
296        Ok(())
297    }
298
299    /// Send a command to the display.
300    async fn command(&mut self, command: u8) -> Result<()> {
301        self.interface
302            .send_commands(DataFormat::U8(&[command]))
303            .await?;
304        Ok(())
305    }
306
307    /// Send an array of bytes to the display.
308    async fn data(&mut self, data: &[u8]) -> Result<()> {
309        self.interface.send_data(DataFormat::U8(data)).await?;
310        self.wait_until_idle().await;
311        Ok(())
312    }
313
314    /// Waits until device isn't busy anymore (busy == HIGH).
315    async fn wait_until_idle(&mut self) {
316        #[cfg(feature = "blocking")]
317        while self.busy.is_high().unwrap_or(true) {
318            self.delay.delay_ms(1)
319        }
320
321        #[cfg(not(feature = "blocking"))]
322        let _ = self.busy.wait_for_low().await;
323    }
324
325    /// Sending a command and the data belonging to it.
326    async fn command_with_data(&mut self, command: u8, data: &[u8]) -> Result<()> {
327        self.command(command).await?;
328        self.data(data).await?;
329        Ok(())
330    }
331
332    /// Send a byte to the display mutiple times.
333    async fn data_x_times(&mut self, data: u8, repetitions: u32) -> Result<()> {
334        let mut iter = iter::repeat(data).take(repetitions as usize);
335        self.interface
336            .send_data(DataFormat::U8Iter(&mut iter))
337            .await?;
338        Ok(())
339    }
340}
341
342/// Functions available only for B/W displays
343#[maybe_async_cfg::maybe(
344    sync(
345        feature = "blocking",
346        keep_self,
347        idents(
348            AsyncWriteOnlyDataCommand(sync = "WriteOnlyDataCommand"),
349            Wait(sync = "InputPin")
350        )
351    ),
352    async(not(feature = "blocking"), keep_self)
353)]
354impl<DI, BSY, RST, DELAY, const WIDTH: u32, const VISIBLE_WIDTH: u32, const HEIGHT: u32>
355    DisplayDriver<DI, BSY, RST, DELAY, WIDTH, VISIBLE_WIDTH, HEIGHT, Color>
356where
357    DI: AsyncWriteOnlyDataCommand,
358    BSY: InputPin + Wait,
359    RST: OutputPin,
360    DELAY: DelayNs,
361{
362    /// Start a fast refresh of the display using the current in-screen buffers.
363    ///
364    /// If the display hasn't done a [`Self::full_refresh`] yet, it will do that first.
365    pub async fn fast_refresh(&mut self) -> Result<()> {
366        if !self.initial_full_refresh_done {
367            // There a bug here which causes the new image to overwrite the existing image which then
368            // fades out over several updates.
369            self.full_refresh().await?;
370        }
371
372        if !self.using_partial_mode {
373            self.command_with_data(command::WRITE_LUT, &lut::LUT_PARTIAL_UPDATE)
374                .await?;
375            self.using_partial_mode = true;
376        }
377        self.command_with_data(command::UPDATE_DISPLAY_CTRL2, &[flag::UNDOCUMENTED])
378            .await?;
379        self.command(command::MASTER_ACTIVATE).await?;
380        self.wait_until_idle().await;
381        Ok(())
382    }
383
384    /// Update the screen with the provided full frame buffer using a full refresh.
385    pub async fn full_update_from_buffer(&mut self, buffer: &[u8]) -> Result<()> {
386        self.write_red_buffer(buffer).await?;
387        self.write_bw_buffer(buffer).await?;
388        self.full_refresh().await?;
389        self.write_red_buffer(buffer).await?;
390        self.write_bw_buffer(buffer).await?;
391        Ok(())
392    }
393
394    /// Update the screen with the provided full frame buffer using a fast refresh.
395    pub async fn fast_update_from_buffer(&mut self, buffer: &[u8]) -> Result<()> {
396        self.write_bw_buffer(buffer).await?;
397        self.fast_refresh().await?;
398        self.write_red_buffer(buffer).await?;
399        self.write_bw_buffer(buffer).await?;
400        Ok(())
401    }
402
403    /// Update the screen with the provided partial frame buffer at the given position using a fast refresh.
404    ///
405    /// `x`, and `width` must be multiples of 8.
406    pub async fn fast_partial_update_from_buffer(
407        &mut self,
408        buffer: &[u8],
409        x: u32,
410        y: u32,
411        width: u32,
412        height: u32,
413    ) -> Result<()> {
414        self.write_partial_bw_buffer(buffer, x, y, width, height)
415            .await?;
416        self.fast_refresh().await?;
417        self.write_partial_red_buffer(buffer, x, y, width, height)
418            .await?;
419        self.write_partial_bw_buffer(buffer, x, y, width, height)
420            .await?;
421        Ok(())
422    }
423
424    /// Update the screen with the provided [`Display`] using a full refresh.
425    #[cfg_attr(docsrs, doc(cfg(feature = "graphics")))]
426    #[cfg(feature = "graphics")]
427    pub async fn full_update<const BUFFER_SIZE: usize>(
428        &mut self,
429        display: &Display<WIDTH, HEIGHT, BUFFER_SIZE, Color>,
430    ) -> Result<()> {
431        self.full_update_from_buffer(display.buffer()).await
432    }
433
434    /// Update the screen with the provided [`Display`] using a fast refresh.
435    #[cfg_attr(docsrs, doc(cfg(feature = "graphics")))]
436    #[cfg(feature = "graphics")]
437    pub async fn fast_update<const BUFFER_SIZE: usize>(
438        &mut self,
439        display: &Display<WIDTH, HEIGHT, BUFFER_SIZE, Color>,
440    ) -> Result<()> {
441        self.fast_update_from_buffer(display.buffer()).await
442    }
443
444    /// Update the screen with the provided partial [`Display`] at the given position using a fast refresh.
445    ///
446    /// `x` and the display width `W` must be multiples of 8.
447    #[cfg_attr(docsrs, doc(cfg(feature = "graphics")))]
448    #[cfg(feature = "graphics")]
449    pub async fn fast_partial_update<const W: u32, const H: u32, const BUFFER_SIZE: usize>(
450        &mut self,
451        display: &Display<W, H, BUFFER_SIZE, Color>,
452        x: u32,
453        y: u32,
454    ) -> Result<()> {
455        self.fast_partial_update_from_buffer(display.buffer(), x, y, W, H)
456            .await
457    }
458}
459
460/// Functions available only for tri-color displays
461#[maybe_async_cfg::maybe(
462    sync(
463        feature = "blocking",
464        keep_self,
465        idents(
466            AsyncWriteOnlyDataCommand(sync = "WriteOnlyDataCommand"),
467            Wait(sync = "InputPin")
468        )
469    ),
470    async(not(feature = "blocking"), keep_self)
471)]
472impl<DI, BSY, RST, DELAY, const WIDTH: u32, const VISIBLE_WIDTH: u32, const HEIGHT: u32>
473    DisplayDriver<DI, BSY, RST, DELAY, WIDTH, VISIBLE_WIDTH, HEIGHT, TriColor>
474where
475    DI: AsyncWriteOnlyDataCommand,
476    BSY: InputPin + Wait,
477    RST: OutputPin,
478    DELAY: DelayNs,
479{
480    /// Update the screen with the provided full frame buffers using a full refresh.
481    pub async fn full_update_from_buffer(
482        &mut self,
483        bw_buffer: &[u8],
484        red_buffer: &[u8],
485    ) -> Result<()> {
486        self.write_red_buffer(red_buffer).await?;
487        self.write_bw_buffer(bw_buffer).await?;
488        self.full_refresh().await?;
489        Ok(())
490    }
491
492    /// Update the screen with the provided [`Display`] using a full refresh.
493    #[cfg_attr(docsrs, doc(cfg(feature = "graphics")))]
494    #[cfg(feature = "graphics")]
495    pub async fn full_update<const BUFFER_SIZE: usize>(
496        &mut self,
497        display: &Display<WIDTH, HEIGHT, BUFFER_SIZE, TriColor>,
498    ) -> Result<()> {
499        self.full_update_from_buffer(display.bw_buffer(), display.red_buffer())
500            .await
501    }
502
503    // TODO: check if partial updates with full refresh are supported
504}