1pub const WIDTH: u32 = 200;
49pub const HEIGHT: u32 = 200;
51pub const DEFAULT_BACKGROUND_COLOR: Color = Color::White;
53const IS_BUSY_LOW: bool = false;
55const SINGLE_BYTE_WRITE: bool = true;
56
57use embedded_hal::{delay::*, digital::*, spi::SpiDevice};
58
59use crate::type_a::{
60 command::Command,
61 constants::{LUT_FULL_UPDATE, LUT_PARTIAL_UPDATE},
62};
63
64use crate::color::Color;
65
66use crate::traits::{RefreshLut, WaveshareDisplay};
67
68use crate::buffer_len;
69use crate::interface::DisplayInterface;
70
71#[cfg(feature = "graphics")]
73pub type Display1in54 = crate::graphics::Display<
74 WIDTH,
75 HEIGHT,
76 false,
77 { buffer_len(WIDTH as usize, HEIGHT as usize) },
78 Color,
79>;
80
81pub struct Epd1in54<SPI, BUSY, DC, RST, DELAY> {
83 interface: DisplayInterface<SPI, BUSY, DC, RST, DELAY, SINGLE_BYTE_WRITE>,
85 background_color: Color,
87 refresh: RefreshLut,
89}
90
91impl<SPI, BUSY, DC, RST, DELAY> Epd1in54<SPI, BUSY, DC, RST, DELAY>
92where
93 SPI: SpiDevice,
94 BUSY: InputPin,
95 DC: OutputPin,
96 RST: OutputPin,
97 DELAY: DelayNs,
98{
99 fn init(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> {
100 self.interface.reset(delay, 10_000, 10_000);
101
102 self.interface.cmd_with_data(
108 spi,
109 Command::DriverOutputControl,
110 &[HEIGHT as u8, (HEIGHT >> 8) as u8, 0x00],
111 )?;
112
113 self.interface
119 .cmd_with_data(spi, Command::BoosterSoftStartControl, &[0xD7, 0xD6, 0x9D])?;
120
121 self.interface
123 .cmd_with_data(spi, Command::WriteVcomRegister, &[0xA8])?;
124
125 self.interface
127 .cmd_with_data(spi, Command::SetDummyLinePeriod, &[0x1A])?;
128
129 self.interface
131 .cmd_with_data(spi, Command::SetGateLineWidth, &[0x08])?;
132
133 self.interface
136 .cmd_with_data(spi, Command::DataEntryModeSetting, &[0x03])?;
137
138 self.set_lut(spi, delay, None)?;
139
140 self.wait_until_idle(spi, delay)?;
141 Ok(())
142 }
143}
144
145impl<SPI, BUSY, DC, RST, DELAY> WaveshareDisplay<SPI, BUSY, DC, RST, DELAY>
146 for Epd1in54<SPI, BUSY, DC, RST, DELAY>
147where
148 SPI: SpiDevice,
149 BUSY: InputPin,
150 DC: OutputPin,
151 RST: OutputPin,
152 DELAY: DelayNs,
153{
154 type DisplayColor = Color;
155 fn width(&self) -> u32 {
156 WIDTH
157 }
158
159 fn height(&self) -> u32 {
160 HEIGHT
161 }
162
163 fn new(
164 spi: &mut SPI,
165 busy: BUSY,
166 dc: DC,
167 rst: RST,
168 delay: &mut DELAY,
169 delay_us: Option<u32>,
170 ) -> Result<Self, SPI::Error> {
171 let interface = DisplayInterface::new(busy, dc, rst, delay_us);
172
173 let mut epd = Epd1in54 {
174 interface,
175 background_color: DEFAULT_BACKGROUND_COLOR,
176 refresh: RefreshLut::Full,
177 };
178
179 epd.init(spi, delay)?;
180
181 Ok(epd)
182 }
183
184 fn wake_up(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> {
185 self.init(spi, delay)
186 }
187
188 fn sleep(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> {
189 self.wait_until_idle(spi, delay)?;
190 self.interface
193 .cmd_with_data(spi, Command::DeepSleepMode, &[0x00])?;
194 Ok(())
195 }
196
197 fn update_frame(
198 &mut self,
199 spi: &mut SPI,
200 buffer: &[u8],
201 delay: &mut DELAY,
202 ) -> Result<(), SPI::Error> {
203 self.wait_until_idle(spi, delay)?;
204 self.use_full_frame(spi, delay)?;
205 self.interface
206 .cmd_with_data(spi, Command::WriteRam, buffer)?;
207 Ok(())
208 }
209
210 fn update_partial_frame(
212 &mut self,
213 spi: &mut SPI,
214 delay: &mut DELAY,
215 buffer: &[u8],
216 x: u32,
217 y: u32,
218 width: u32,
219 height: u32,
220 ) -> Result<(), SPI::Error> {
221 self.wait_until_idle(spi, delay)?;
222 self.set_ram_area(spi, delay, x, y, x + width, y + height)?;
223 self.set_ram_counter(spi, delay, x, y)?;
224
225 self.interface
226 .cmd_with_data(spi, Command::WriteRam, buffer)?;
227 Ok(())
228 }
229
230 fn display_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> {
231 self.wait_until_idle(spi, delay)?;
232 self.interface
235 .cmd_with_data(spi, Command::DisplayUpdateControl2, &[0xC4])?;
236
237 self.interface.cmd(spi, Command::MasterActivation)?;
238 self.interface.cmd(spi, Command::Nop)?;
241 Ok(())
242 }
243
244 fn update_and_display_frame(
245 &mut self,
246 spi: &mut SPI,
247 buffer: &[u8],
248 delay: &mut DELAY,
249 ) -> Result<(), SPI::Error> {
250 self.update_frame(spi, buffer, delay)?;
251 self.display_frame(spi, delay)?;
252 Ok(())
253 }
254
255 fn clear_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> {
256 self.wait_until_idle(spi, delay)?;
257 self.use_full_frame(spi, delay)?;
258
259 let color = self.background_color.get_byte_value();
261
262 self.interface.cmd(spi, Command::WriteRam)?;
263 self.interface
264 .data_x_times(spi, color, WIDTH / 8 * HEIGHT)?;
265 Ok(())
266 }
267
268 fn set_background_color(&mut self, background_color: Color) {
269 self.background_color = background_color;
270 }
271
272 fn background_color(&self) -> &Color {
273 &self.background_color
274 }
275
276 fn set_lut(
277 &mut self,
278 spi: &mut SPI,
279 delay: &mut DELAY,
280 refresh_rate: Option<RefreshLut>,
281 ) -> Result<(), SPI::Error> {
282 if let Some(refresh_lut) = refresh_rate {
283 self.refresh = refresh_lut;
284 }
285 match self.refresh {
286 RefreshLut::Full => self.set_lut_helper(spi, delay, &LUT_FULL_UPDATE),
287 RefreshLut::Quick => self.set_lut_helper(spi, delay, &LUT_PARTIAL_UPDATE),
288 }
289 }
290
291 fn wait_until_idle(&mut self, _spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> {
292 self.interface.wait_until_idle(delay, IS_BUSY_LOW);
293 Ok(())
294 }
295}
296
297impl<SPI, BUSY, DC, RST, DELAY> Epd1in54<SPI, BUSY, DC, RST, DELAY>
298where
299 SPI: SpiDevice,
300 BUSY: InputPin,
301 DC: OutputPin,
302 RST: OutputPin,
303 DELAY: DelayNs,
304{
305 pub(crate) fn use_full_frame(
306 &mut self,
307 spi: &mut SPI,
308 delay: &mut DELAY,
309 ) -> Result<(), SPI::Error> {
310 self.set_ram_area(spi, delay, 0, 0, WIDTH - 1, HEIGHT - 1)?;
312
313 self.set_ram_counter(spi, delay, 0, 0)
315 }
316
317 pub(crate) fn set_ram_area(
318 &mut self,
319 spi: &mut SPI,
320 delay: &mut DELAY,
321 start_x: u32,
322 start_y: u32,
323 end_x: u32,
324 end_y: u32,
325 ) -> Result<(), SPI::Error> {
326 self.wait_until_idle(spi, delay)?;
327 assert!(start_x < end_x);
328 assert!(start_y < end_y);
329
330 self.interface.cmd_with_data(
333 spi,
334 Command::SetRamXAddressStartEndPosition,
335 &[(start_x >> 3) as u8, (end_x >> 3) as u8],
336 )?;
337
338 self.interface.cmd_with_data(
340 spi,
341 Command::SetRamYAddressStartEndPosition,
342 &[
343 start_y as u8,
344 (start_y >> 8) as u8,
345 end_y as u8,
346 (end_y >> 8) as u8,
347 ],
348 )?;
349 Ok(())
350 }
351
352 pub(crate) fn set_ram_counter(
353 &mut self,
354 spi: &mut SPI,
355 delay: &mut DELAY,
356 x: u32,
357 y: u32,
358 ) -> Result<(), SPI::Error> {
359 self.wait_until_idle(spi, delay)?;
360 self.interface
363 .cmd_with_data(spi, Command::SetRamXAddressCounter, &[(x >> 3) as u8])?;
364
365 self.interface.cmd_with_data(
367 spi,
368 Command::SetRamYAddressCounter,
369 &[y as u8, (y >> 8) as u8],
370 )?;
371 Ok(())
372 }
373
374 fn set_lut_helper(
375 &mut self,
376 spi: &mut SPI,
377 delay: &mut DELAY,
378 buffer: &[u8],
379 ) -> Result<(), SPI::Error> {
380 self.wait_until_idle(spi, delay)?;
381 assert!(buffer.len() == 30);
382
383 self.interface
384 .cmd_with_data(spi, Command::WriteLutRegister, buffer)?;
385 Ok(())
386 }
387}
388
389#[cfg(test)]
390mod tests {
391 use super::*;
392
393 #[test]
394 fn epd_size() {
395 assert_eq!(WIDTH, 200);
396 assert_eq!(HEIGHT, 200);
397 assert_eq!(DEFAULT_BACKGROUND_COLOR, Color::White);
398 }
399}