1pub const WIDTH: u32 = 128;
59pub const HEIGHT: u32 = 296;
61pub const DEFAULT_BACKGROUND_COLOR: Color = Color::White;
63const IS_BUSY_LOW: bool = false;
64const SINGLE_BYTE_WRITE: bool = true;
65
66const LUT_PARTIAL_2IN9: [u8; 159] = [
67 0x0, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x80, 0x0, 0x0, 0x0, 0x0,
68 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
69 0x0, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
70 0x0, 0x0, 0x0, 0x0, 0x0, 0x0A, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
71 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
72 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
73 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
74 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x22, 0x22, 0x22, 0x22, 0x22,
75 0x22, 0x0, 0x0, 0x0, 0x22, 0x17, 0x41, 0xB0, 0x32, 0x36,
76];
77
78const WS_20_30: [u8; 159] = [
79 0x80, 0x66, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x0, 0x0, 0x0, 0x10, 0x66, 0x0, 0x0, 0x0, 0x0,
80 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0x80, 0x66, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x0, 0x0, 0x0,
81 0x10, 0x66, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
82 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x14, 0x8, 0x0, 0x0, 0x0, 0x0, 0x1, 0xA, 0xA, 0x0, 0xA, 0xA, 0x0,
83 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
84 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
85 0x0, 0x0, 0x0, 0x0, 0x0, 0x14, 0x8, 0x0, 0x1, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1,
86 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x44, 0x44, 0x44, 0x44,
87 0x44, 0x44, 0x0, 0x0, 0x0, 0x22, 0x17, 0x41, 0x0, 0x32, 0x36,
88];
89
90use embedded_hal::{delay::*, digital::*, spi::SpiDevice};
91
92use crate::type_a::command::Command;
93
94use crate::color::Color;
95
96use crate::traits::*;
97
98use crate::buffer_len;
99use crate::interface::DisplayInterface;
100use crate::traits::QuickRefresh;
101
102#[cfg(feature = "graphics")]
104pub type Display2in9 = crate::graphics::Display<
105 WIDTH,
106 HEIGHT,
107 false,
108 { buffer_len(WIDTH as usize, HEIGHT as usize) },
109 Color,
110>;
111
112pub struct Epd2in9<SPI, BUSY, DC, RST, DELAY> {
115 interface: DisplayInterface<SPI, BUSY, DC, RST, DELAY, SINGLE_BYTE_WRITE>,
117 background_color: Color,
119 refresh: RefreshLut,
121}
122
123impl<SPI, BUSY, DC, RST, DELAY> Epd2in9<SPI, BUSY, DC, RST, DELAY>
124where
125 SPI: SpiDevice,
126 BUSY: InputPin,
127 DC: OutputPin,
128 RST: OutputPin,
129 DELAY: DelayNs,
130{
131 fn init(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> {
132 self.interface.reset(delay, 10_000, 2_000);
133
134 self.wait_until_idle(spi, delay)?;
135 self.interface.cmd(spi, Command::SwReset)?;
136 self.wait_until_idle(spi, delay)?;
137
138 self.interface
144 .cmd_with_data(spi, Command::DriverOutputControl, &[0x27, 0x01, 0x00])?;
145
146 self.interface
149 .cmd_with_data(spi, Command::DataEntryModeSetting, &[0x03])?;
150
151 self.set_ram_area(spi, 0, 0, WIDTH - 1, HEIGHT - 1)?;
152
153 self.interface
154 .cmd_with_data(spi, Command::DisplayUpdateControl1, &[0x00, 0x80])?;
155
156 self.set_ram_counter(spi, delay, 0, 0)?;
157
158 self.wait_until_idle(spi, delay)?;
159
160 self.set_lut_helper(spi, delay, &WS_20_30[0..153])?;
162 self.interface
163 .cmd_with_data(spi, Command::WriteLutRegisterEnd, &WS_20_30[153..154])?;
164 self.interface
165 .cmd_with_data(spi, Command::GateDrivingVoltage, &WS_20_30[154..155])?;
166 self.interface
167 .cmd_with_data(spi, Command::SourceDrivingVoltage, &WS_20_30[155..158])?;
168 self.interface
169 .cmd_with_data(spi, Command::WriteVcomRegister, &WS_20_30[158..159])?;
170
171 Ok(())
172 }
173}
174
175impl<SPI, BUSY, DC, RST, DELAY> WaveshareDisplay<SPI, BUSY, DC, RST, DELAY>
176 for Epd2in9<SPI, BUSY, DC, RST, DELAY>
177where
178 SPI: SpiDevice,
179 BUSY: InputPin,
180 DC: OutputPin,
181 RST: OutputPin,
182 DELAY: DelayNs,
183{
184 type DisplayColor = Color;
185 fn width(&self) -> u32 {
186 WIDTH
187 }
188
189 fn height(&self) -> u32 {
190 HEIGHT
191 }
192
193 fn new(
194 spi: &mut SPI,
195 busy: BUSY,
196 dc: DC,
197 rst: RST,
198 delay: &mut DELAY,
199 delay_us: Option<u32>,
200 ) -> Result<Self, SPI::Error> {
201 let interface = DisplayInterface::new(busy, dc, rst, delay_us);
202
203 let mut epd = Epd2in9 {
204 interface,
205 background_color: DEFAULT_BACKGROUND_COLOR,
206 refresh: RefreshLut::Full,
207 };
208
209 epd.init(spi, delay)?;
210
211 Ok(epd)
212 }
213
214 fn sleep(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> {
215 self.wait_until_idle(spi, delay)?;
216 self.interface
218 .cmd_with_data(spi, Command::DeepSleepMode, &[0x01])?;
219 Ok(())
220 }
221
222 fn wake_up(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> {
223 self.init(spi, delay)?;
224 Ok(())
225 }
226
227 fn update_frame(
228 &mut self,
229 spi: &mut SPI,
230 buffer: &[u8],
231 delay: &mut DELAY,
232 ) -> Result<(), SPI::Error> {
233 self.wait_until_idle(spi, delay)?;
234 self.interface.cmd_with_data(spi, Command::WriteRam, buffer)
235 }
236
237 fn update_partial_frame(
238 &mut self,
239 spi: &mut SPI,
240 delay: &mut DELAY,
241 buffer: &[u8],
242 x: u32,
243 y: u32,
244 width: u32,
245 height: u32,
246 ) -> Result<(), SPI::Error> {
247 self.wait_until_idle(spi, delay)?;
249 self.set_ram_area(spi, x, y, x + width, y + height)?;
250 self.set_ram_counter(spi, delay, x, y)?;
251
252 self.interface
253 .cmd_with_data(spi, Command::WriteRam, buffer)?;
254 Ok(())
255 }
256
257 fn display_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> {
259 self.wait_until_idle(spi, delay)?;
260 self.interface
262 .cmd_with_data(spi, Command::DisplayUpdateControl2, &[0xC7])?;
263 self.interface.cmd(spi, Command::MasterActivation)?;
264 self.wait_until_idle(spi, delay)?;
265 Ok(())
266 }
267
268 fn update_and_display_frame(
269 &mut self,
270 spi: &mut SPI,
271 buffer: &[u8],
272 delay: &mut DELAY,
273 ) -> Result<(), SPI::Error> {
274 self.update_frame(spi, buffer, delay)?;
275 self.display_frame(spi, delay)?;
276 Ok(())
277 }
278
279 fn clear_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> {
280 self.wait_until_idle(spi, delay)?;
281
282 let color = self.background_color.get_byte_value();
284
285 self.interface.cmd(spi, Command::WriteRam)?;
286 self.interface
287 .data_x_times(spi, color, WIDTH / 8 * HEIGHT)?;
288 self.interface.cmd(spi, Command::WriteRam2)?;
289 self.interface.data_x_times(spi, color, WIDTH / 8 * HEIGHT)
290 }
291
292 fn set_background_color(&mut self, background_color: Color) {
293 self.background_color = background_color;
294 }
295
296 fn background_color(&self) -> &Color {
297 &self.background_color
298 }
299
300 fn set_lut(
301 &mut self,
302 _spi: &mut SPI,
303 _delay: &mut DELAY,
304 refresh_rate: Option<RefreshLut>,
305 ) -> Result<(), SPI::Error> {
306 if let Some(refresh_lut) = refresh_rate {
307 self.refresh = refresh_lut;
308 }
309 Ok(())
310 }
311
312 fn wait_until_idle(&mut self, _spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> {
313 self.interface.wait_until_idle(delay, IS_BUSY_LOW);
314 Ok(())
315 }
316}
317
318impl<SPI, BUSY, DC, RST, DELAY> Epd2in9<SPI, BUSY, DC, RST, DELAY>
319where
320 SPI: SpiDevice,
321 BUSY: InputPin,
322 DC: OutputPin,
323 RST: OutputPin,
324 DELAY: DelayNs,
325{
326 fn use_full_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> {
327 self.set_ram_area(spi, 0, 0, WIDTH - 1, HEIGHT - 1)?;
329
330 self.set_ram_counter(spi, delay, 0, 0)
332 }
333
334 fn set_ram_area(
335 &mut self,
336 spi: &mut SPI,
337 start_x: u32,
338 start_y: u32,
339 end_x: u32,
340 end_y: u32,
341 ) -> Result<(), SPI::Error> {
342 assert!(start_x < end_x);
343 assert!(start_y < end_y);
344
345 self.interface.cmd_with_data(
348 spi,
349 Command::SetRamXAddressStartEndPosition,
350 &[(start_x >> 3) as u8, (end_x >> 3) as u8],
351 )?;
352
353 self.interface.cmd_with_data(
355 spi,
356 Command::SetRamYAddressStartEndPosition,
357 &[
358 start_y as u8,
359 (start_y >> 8) as u8,
360 end_y as u8,
361 (end_y >> 8) as u8,
362 ],
363 )
364 }
365
366 fn set_ram_counter(
367 &mut self,
368 spi: &mut SPI,
369 delay: &mut DELAY,
370 x: u32,
371 y: u32,
372 ) -> Result<(), SPI::Error> {
373 self.wait_until_idle(spi, delay)?;
374 self.interface
377 .cmd_with_data(spi, Command::SetRamXAddressCounter, &[x as u8])?;
378
379 self.interface.cmd_with_data(
381 spi,
382 Command::SetRamYAddressCounter,
383 &[y as u8, (y >> 8) as u8],
384 )?;
385 Ok(())
386 }
387
388 fn set_lut_helper(
390 &mut self,
391 spi: &mut SPI,
392 delay: &mut DELAY,
393 buffer: &[u8],
394 ) -> Result<(), SPI::Error> {
395 self.wait_until_idle(spi, delay)?;
396 self.interface
397 .cmd_with_data(spi, Command::WriteLutRegister, buffer)?;
398 self.wait_until_idle(spi, delay)?;
399 Ok(())
400 }
401}
402
403impl<SPI, BUSY, DC, RST, DELAY> QuickRefresh<SPI, BUSY, DC, RST, DELAY>
404 for Epd2in9<SPI, BUSY, DC, RST, DELAY>
405where
406 SPI: SpiDevice,
407 BUSY: InputPin,
408 DC: OutputPin,
409 RST: OutputPin,
410 DELAY: DelayNs,
411{
412 fn update_old_frame(
414 &mut self,
415 spi: &mut SPI,
416 buffer: &[u8],
417 delay: &mut DELAY,
418 ) -> Result<(), SPI::Error> {
419 self.wait_until_idle(spi, delay)?;
420 self.interface
421 .cmd_with_data(spi, Command::WriteRam2, buffer)
422 }
423
424 fn update_new_frame(
426 &mut self,
427 spi: &mut SPI,
428 buffer: &[u8],
429 delay: &mut DELAY,
430 ) -> Result<(), SPI::Error> {
431 self.wait_until_idle(spi, delay)?;
432 self.interface.reset(delay, 10_000, 2_000);
433
434 self.set_lut_helper(spi, delay, &LUT_PARTIAL_2IN9)?;
435 self.interface.cmd_with_data(
436 spi,
437 Command::WriteOtpSelection,
438 &[0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00],
439 )?;
440 self.interface
441 .cmd_with_data(spi, Command::BorderWaveformControl, &[0x80])?;
442 self.interface
443 .cmd_with_data(spi, Command::DisplayUpdateControl2, &[0xC0])?;
444 self.interface.cmd(spi, Command::MasterActivation)?;
445
446 self.wait_until_idle(spi, delay)?;
447
448 self.use_full_frame(spi, delay)?;
449
450 self.interface
451 .cmd_with_data(spi, Command::WriteRam, buffer)?;
452 Ok(())
453 }
454
455 fn display_new_frame(&mut self, spi: &mut SPI, delay: &mut DELAY) -> Result<(), SPI::Error> {
457 self.wait_until_idle(spi, delay)?;
458 self.interface
459 .cmd_with_data(spi, Command::DisplayUpdateControl2, &[0x0F])?;
460 self.interface.cmd(spi, Command::MasterActivation)?;
461 self.wait_until_idle(spi, delay)?;
462 Ok(())
463 }
464
465 fn update_and_display_new_frame(
467 &mut self,
468 spi: &mut SPI,
469 buffer: &[u8],
470 delay: &mut DELAY,
471 ) -> Result<(), SPI::Error> {
472 self.update_new_frame(spi, buffer, delay)?;
473 self.display_new_frame(spi, delay)?;
474 Ok(())
475 }
476
477 #[allow(unused)]
479 fn update_partial_old_frame(
480 &mut self,
481 spi: &mut SPI,
482 delay: &mut DELAY,
483 buffer: &[u8],
484 x: u32,
485 y: u32,
486 width: u32,
487 height: u32,
488 ) -> Result<(), SPI::Error> {
489 unimplemented!()
491 }
492
493 #[allow(unused)]
495 fn update_partial_new_frame(
496 &mut self,
497 spi: &mut SPI,
498 delay: &mut DELAY,
499 buffer: &[u8],
500 x: u32,
501 y: u32,
502 width: u32,
503 height: u32,
504 ) -> Result<(), SPI::Error> {
505 unimplemented!()
507 }
508
509 #[allow(unused)]
511 fn clear_partial_frame(
512 &mut self,
513 spi: &mut SPI,
514 delay: &mut DELAY,
515 x: u32,
516 y: u32,
517 width: u32,
518 height: u32,
519 ) -> Result<(), SPI::Error> {
520 unimplemented!()
522 }
523}
524
525#[cfg(test)]
526mod tests {
527 use super::*;
528
529 #[test]
530 fn epd_size() {
531 assert_eq!(WIDTH, 128);
532 assert_eq!(HEIGHT, 296);
533 assert_eq!(DEFAULT_BACKGROUND_COLOR, Color::White);
534 }
535}