1#![crate_type = "lib"]
90#![cfg_attr(test, allow(unused_imports))]
91#![cfg_attr(not(test), no_std)]
92
93#![deny(missing_docs)]
94
95use core::convert::TryInto;
96use embedded_hal::{
97 blocking::delay::DelayUs, blocking::spi, digital::v2::InputPin, digital::v2::OutputPin,
98};
99use num_derive::ToPrimitive;
100
101#[derive(Debug)]
102pub enum Error<CommError, PinError> {
104 Comm(CommError),
106 Pin(PinError),
108}
109
110#[derive(ToPrimitive)]
112enum Instruction {
113 GateDrivingVoltageControl = 0x03,
114 DeepSleepModeDisable = 0x10,
115 DateEntryModeSetting = 17,
116 MasterActivation = 0x20,
117 DisplayUpdateDisableRamBypass = 0x21,
118 DisplayUpdateControl2 = 0x22,
119 WriteRam = 0x24, WriteVCOMRegister = 44,
121 WriteLUTRegister = 50,
122 BorderWaveform = 0x3C,
123 SetRamXStartEndAddress = 0x44, SetRamYStartEndAddress = 69,
125 SetRamXAddressCounter = 0x4E, SetRamYAddressCounter = 0x4F, BoosterInternalFeedbackSel = 0xF0, }
129
130#[derive(ToPrimitive, Clone, Copy)]
131pub enum Color {
133 #[doc(hidden)]
134 BLACK = 0b00,
135 #[doc(hidden)]
136 DARKGRAY = 0b01,
137 #[doc(hidden)]
138 LIGHTGRAY = 0b10,
139 #[doc(hidden)]
140 WHITE = 0b11,
141}
142
143const WF_LUT: [u8; 90] = [
145 0x82, 0x00, 0x00, 0x00, 0xAA, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0x00,
146 0x55, 0xAA, 0xAA, 0x00, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
147 0xAA, 0xAA, 0xAA, 0xAA, 0x15, 0x15, 0x15, 0x15, 0x05, 0x05, 0x05, 0x05, 0x01, 0x01, 0x01, 0x01,
148 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
149 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
150 0x41, 0x45, 0xF1, 0xFF, 0x5F, 0x55, 0x01, 0x00, 0x00, 0x00,
151];
152
153const WIDTH: u16 = 172;
155const GEOM_WIDTH: i32 = WIDTH as i32;
156const HEIGHT: u16 = 18;
159const GEOM_HEIGHT: i32 = (4 * HEIGHT) as i32;
160
161fn pixel_to_byte(position: usize, color: u8) -> u8 {
163 let p = position << 1;
164 color << p
165}
166
167fn position_mask(position: usize) -> u8 {
169 let val: u8 = 0b000_0011;
170 let p = position << 1;
171 !(val << p)
172}
173
174fn overwrite_pixel_in_byte(byte: u8, position: usize, color: u8) -> u8 {
176 let val: u8 = byte & position_mask(position);
177 val | pixel_to_byte(position, color)
178}
179
180pub struct GDE021A1<SPI, RST, CS, DC, BSY>
207where
208 SPI: spi::Write<u8>,
209 RST: OutputPin,
210 CS: OutputPin,
211 DC: OutputPin,
212 BSY: InputPin,
213{
214 spi: SPI,
216 rst: RST,
218 cs: Option<CS>,
220 bsy: BSY,
222 dc: DC,
224 buffer: [u8; (WIDTH * HEIGHT) as usize],
226}
227
228impl<SPI, RST, CS, DC, BSY, PinError, SPIError> GDE021A1<SPI, RST, CS, DC, BSY>
229where
230 SPI: spi::Write<u8, Error = SPIError>,
231 RST: OutputPin<Error = PinError>,
232 CS: OutputPin<Error = PinError>,
233 DC: OutputPin<Error = PinError>,
234 BSY: InputPin<Error = PinError>,
235{
236 pub fn new(spi: SPI, rst: RST, cs: Option<CS>, dc: DC, bsy: BSY) -> Self {
238 GDE021A1 {
239 spi,
240 rst,
241 cs,
242 dc,
243 bsy,
244 buffer: [0xFF; (WIDTH * HEIGHT) as usize],
245 }
246 }
247
248 pub fn init(&mut self, delay: &mut dyn DelayUs<u32>) -> Result<(), Error<SPIError, PinError>> {
250 self.enable_cs(delay)?;
251 self.hard_reset(delay)?;
252 delay.delay_us(10_000); self.write_command(Instruction::DeepSleepModeDisable)?;
255 self.write_data(0x00)?; self.write_command(Instruction::DateEntryModeSetting)?;
257 self.write_data(0x03)?;
258 self.write_command(Instruction::SetRamXStartEndAddress)?;
259 self.write_data(0x00)?; self.write_data(0x11)?;
262 self.write_command(Instruction::SetRamYStartEndAddress)?;
263 self.write_data(0x00)?; self.write_data(0xAB)?; self.write_command(Instruction::SetRamXAddressCounter)?;
266 self.write_data(0x00)?;
267 self.write_command(Instruction::SetRamYAddressCounter)?;
268 self.write_data(0x00)?;
269 self.write_command(Instruction::BoosterInternalFeedbackSel)?;
270 self.write_data(0x1F)?; self.write_command(Instruction::DisplayUpdateDisableRamBypass)?;
272 self.write_data(0x03)?;
274 self.write_command(Instruction::WriteVCOMRegister)?;
275 self.write_data(0xA0)?;
276 self.write_command(Instruction::BorderWaveform)?;
277 self.write_data(0x64)?;
278 self.write_command(Instruction::WriteLUTRegister)?;
279 for elem in WF_LUT.iter() {
280 self.write_data(*elem)?;
281 }
282
283 self.disable_cs(delay)?;
284 Ok(())
285 }
286
287 pub fn clear(&mut self) {
289 self.clear_with_color(Color::WHITE);
290 }
291
292 pub fn refresh(
299 &mut self,
300 delay: &mut dyn DelayUs<u32>,
301 ) -> Result<(), Error<SPIError, PinError>> {
302 self.write_buffer(delay)?;
303
304 self.enable_cs(delay)?;
305
306 self.write_command(Instruction::DisplayUpdateDisableRamBypass)?;
307 self.write_data(0x03)?; self.write_command(Instruction::DisplayUpdateControl2)?;
309 self.write_data(0xC4)?; self.write_command(Instruction::MasterActivation)?;
311
312 self.disable_cs(delay)?;
313 self.busy_wait();
314
315 self.close_charge_pump(delay)?;
316
317 Ok(())
318 }
319
320 fn enable_cs(&mut self, delay: &mut dyn DelayUs<u32>) -> Result<(), Error<SPIError, PinError>> {
322 if let Some(cs) = self.cs.as_mut() {
323 cs.set_low().map_err(Error::Pin)?;
324 delay.delay_us(100);
325 }
326 Ok(())
327 }
328
329 fn disable_cs(
331 &mut self,
332 delay: &mut dyn DelayUs<u32>,
333 ) -> Result<(), Error<SPIError, PinError>> {
334 if let Some(cs) = self.cs.as_mut() {
335 delay.delay_us(100);
336 cs.set_high().map_err(Error::Pin)?;
337 }
338 Ok(())
339 }
340
341 fn hard_reset(
343 &mut self,
344 delay: &mut dyn DelayUs<u32>,
345 ) -> Result<(), Error<SPIError, PinError>> {
346 self.rst.set_low().map_err(Error::Pin)?;
347 delay.delay_us(10_000);
348 self.rst.set_high().map_err(Error::Pin)?;
349 delay.delay_us(10_000);
350 Ok(())
351 }
352
353 fn write_command(&mut self, command: Instruction) -> Result<(), Error<SPIError, PinError>> {
354 self.dc.set_low().map_err(Error::Pin)?;
355 self.spi.write(&[command as u8]).map_err(Error::Comm)?;
356 Ok(())
357 }
358
359 fn write_data(&mut self, data: u8) -> Result<(), Error<SPIError, PinError>> {
360 self.dc.set_high().map_err(Error::Pin)?;
361 self.spi.write(&[data]).map_err(Error::Comm)?;
362 Ok(())
363 }
364
365 fn clear_with_color(&mut self, color: Color) {
367 let color: u8 = color as u8;
368 let val: u8 = pixel_to_byte(0, color);
369 let val: u8 = pixel_to_byte(1, color) | val;
370 let val: u8 = pixel_to_byte(2, color) | val;
371 let val: u8 = pixel_to_byte(3, color) | val;
372 for byte in self.buffer.iter_mut() {
373 *byte = val;
374 }
375 }
376
377 fn set_display_window(
379 &mut self,
380 x_pos: u8,
381 y_pos: u8,
382 width: u8,
383 height: u8,
384 ) -> Result<(), Error<SPIError, PinError>> {
385 self.write_command(Instruction::SetRamXStartEndAddress)?;
387 self.write_data(y_pos)?;
388 self.write_data(height)?;
389 self.write_command(Instruction::SetRamYStartEndAddress)?;
391 self.write_data(x_pos)?;
392 self.write_data(width)?;
393 self.write_command(Instruction::SetRamXAddressCounter)?;
395 self.write_data(y_pos)?;
396 self.write_command(Instruction::SetRamYAddressCounter)?;
398 self.write_data(x_pos)?;
399 Ok(())
400 }
401
402 fn write_buffer(
404 &mut self,
405 delay: &mut dyn DelayUs<u32>,
406 ) -> Result<(), Error<SPIError, PinError>> {
407 self.enable_cs(delay)?;
408
409 self.set_display_window(0, 0, WIDTH as u8 - 1, HEIGHT as u8 - 1)?;
411 self.write_command(Instruction::WriteRam)?;
413 for elem in 0..self.buffer.len() {
414 self.write_data(self.buffer[elem])?;
415 }
416
417 self.disable_cs(delay)?;
418
419 Ok(())
420 }
421
422 pub fn busy_wait(&self) {
424 while match self.bsy.is_low() {
425 Ok(x) => x,
426 _ => false,
427 } {}
428 }
429
430 fn close_charge_pump(
432 &mut self,
433 delay: &mut dyn DelayUs<u32>,
434 ) -> Result<(), Error<SPIError, PinError>> {
435 self.enable_cs(delay)?;
436
437 self.write_command(Instruction::DisplayUpdateControl2)?;
438 self.write_data(0x03)?; self.write_command(Instruction::MasterActivation)?;
440
441 self.disable_cs(delay)?;
442 delay.delay_us(400_000);
443
444 Ok(())
445 }
446
447 pub fn alt_init(
449 &mut self,
450 delay: &mut dyn DelayUs<u32>,
451 ) -> Result<(), Error<SPIError, PinError>> {
452 self.enable_cs(delay)?;
453 self.hard_reset(delay)?;
454 delay.delay_us(1_000); self.write_command(Instruction::DisplayUpdateDisableRamBypass)?;
457 self.write_data(0x8F)?;
458 self.write_command(Instruction::GateDrivingVoltageControl)?;
459 self.write_data(0x00)?;
460 self.write_command(Instruction::WriteRam)?;
461 for _i in 0..5760 {
462 self.write_data(0xFF)?;
463 }
464 self.write_data(0xF8)?;
465 self.write_command(Instruction::MasterActivation)?;
466
467 self.disable_cs(delay)?;
468 Ok(())
469 }
470}
471
472#[cfg(feature = "graphics")]
473extern crate embedded_graphics;
474#[cfg(feature = "graphics")]
475use self::embedded_graphics::{
476 prelude::RawData,
477 drawable,
478 geometry::Size,
479 pixelcolor::{BinaryColor, Gray2, raw::RawU2 },
480 DrawTarget
481};
482
483#[cfg(feature = "graphics")]
484impl<SPI, CS, RST, DC, BSY, PinError, SPIError> DrawTarget<Gray2>
485 for GDE021A1<SPI, CS, RST, DC, BSY>
486where
487 SPI: spi::Write<u8, Error = SPIError>,
488 RST: OutputPin<Error = PinError>,
489 CS: OutputPin<Error = PinError>,
490 DC: OutputPin<Error = PinError>,
491 BSY: InputPin<Error = PinError>,
492{
493 type Error = Error<SPIError, PinError>;
494
495 fn size(&self) -> Size {
496 Size::new(WIDTH.try_into().unwrap(), (4 * HEIGHT).try_into().unwrap())
497 }
498
499 fn draw_pixel(
500 &mut self,
501 pixel: drawable::Pixel<Gray2>,
502 ) -> Result<(), Error<SPIError, PinError>> {
503 let drawable::Pixel(coord, color) = pixel;
504 if let Ok((x @ 0..=GEOM_WIDTH, y @ 0..=GEOM_HEIGHT)) = coord.try_into() {
505 let r : RawU2 = color.into();
506 let c : u8 = r.into_inner();
507 let p: usize = (y % 4).try_into().unwrap();
509 let p: usize = 3 - p;
510 let y: usize = (y / 4).try_into().unwrap();
511 let x: usize = (GEOM_WIDTH - x).try_into().unwrap();
513 let byte: u8 = self.buffer[y + x * HEIGHT as usize];
514 self.buffer[y + x * HEIGHT as usize] = overwrite_pixel_in_byte(byte, p, c);
515 }
516 Ok(())
517 }
518}
519
520
521impl<SPI, CS, RST, DC, BSY, PinError, SPIError> DrawTarget<BinaryColor>
522 for GDE021A1<SPI, CS, RST, DC, BSY>
523where
524 SPI: spi::Write<u8, Error = SPIError>,
525 RST: OutputPin<Error = PinError>,
526 CS: OutputPin<Error = PinError>,
527 DC: OutputPin<Error = PinError>,
528 BSY: InputPin<Error = PinError>,
529{
530 type Error = Error<SPIError, PinError>;
531
532 fn size(&self) -> Size {
533 Size::new(WIDTH.try_into().unwrap(), (4 * HEIGHT).try_into().unwrap())
534 }
535
536 fn draw_pixel(
537 &mut self,
538 pixel: drawable::Pixel<BinaryColor>,
539 ) -> Result<(), Error<SPIError, PinError>> {
540 let drawable::Pixel(coord, color) = pixel;
541 if let Ok((x @ 0..=GEOM_WIDTH, y @ 0..=GEOM_HEIGHT)) = coord.try_into() {
542 let c: Color = match color {
543 BinaryColor::On => Color::BLACK,
544 BinaryColor::Off => Color::WHITE,
545 };
546 let c: u8 = c as u8;
547 let p: usize = (y % 4).try_into().unwrap();
549 let p: usize = 3 - p;
550 let y: usize = (y / 4).try_into().unwrap();
551 let x: usize = (GEOM_WIDTH - x).try_into().unwrap();
553 let byte: u8 = self.buffer[y + x * HEIGHT as usize];
554 self.buffer[y + x * HEIGHT as usize] = overwrite_pixel_in_byte(byte, p, c);
555 }
556 Ok(())
557 }
558}
559
560#[cfg(test)]
561mod tests {
562
563 use crate::{pixel_to_byte, position_mask, Color};
564
565 #[test]
566 fn it_should_convert_pixel_to_byte_at_zero_pos() {
567 assert_eq!(0b0000_0000, pixel_to_byte(0, Color::BLACK as u8));
568 assert_eq!(0b0000_0001, pixel_to_byte(0, Color::DARKGRAY as u8));
569 assert_eq!(0b0000_0010, pixel_to_byte(0, Color::LIGHTGRAY as u8));
570 assert_eq!(0b0000_0011, pixel_to_byte(0, Color::WHITE as u8));
571 }
572
573 #[test]
574 fn it_should_convert_pixel_to_byte_at_one_pos() {
575 assert_eq!(0b0000_0000, pixel_to_byte(1, Color::BLACK as u8));
576 assert_eq!(0b0000_0100, pixel_to_byte(1, Color::DARKGRAY as u8));
577 assert_eq!(0b0000_1000, pixel_to_byte(1, Color::LIGHTGRAY as u8));
578 assert_eq!(0b0000_1100, pixel_to_byte(1, Color::WHITE as u8));
579 }
580
581 #[test]
582 fn it_should_convert_pixel_to_byte_at_two_pos() {
583 assert_eq!(0b0000_0000, pixel_to_byte(2, Color::BLACK as u8));
584 assert_eq!(0b0001_0000, pixel_to_byte(2, Color::DARKGRAY as u8));
585 assert_eq!(0b0010_0000, pixel_to_byte(2, Color::LIGHTGRAY as u8));
586 assert_eq!(0b0011_0000, pixel_to_byte(2, Color::WHITE as u8));
587 }
588
589 #[test]
590 fn it_should_convert_pixel_to_byte_at_three_pos() {
591 assert_eq!(0b0000_0000, pixel_to_byte(3, Color::BLACK as u8));
592 assert_eq!(0b0100_0000, pixel_to_byte(3, Color::DARKGRAY as u8));
593 assert_eq!(0b1000_0000, pixel_to_byte(3, Color::LIGHTGRAY as u8));
594 assert_eq!(0b1100_0000, pixel_to_byte(3, Color::WHITE as u8));
595 }
596
597 #[test]
598 fn it_should_compute_a_position_mask() {
599 assert_eq!(0b1111_1100, position_mask(0));
600 assert_eq!(0b1111_0011, position_mask(1));
601 assert_eq!(0b1100_1111, position_mask(2));
602 assert_eq!(0b0011_1111, position_mask(3));
603 }
604}