Merge branch 'main' into main
commit
434f1bcd20
34
CHANGELOG.md
34
CHANGELOG.md
|
|
@ -13,12 +13,13 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||||
- Added Epd 7in5 HD support
|
- Added Epd 7in5 HD support
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
- Use specific ParseColorError instead of ()
|
- Use specific ParseColorError instead of ()
|
||||||
- EPD4in2: Don't set the resolution (and some more) over and over again (#48)
|
- Epd4in2: Don't set the resolution (and some more) over and over again (#48)
|
||||||
|
- Removed `#[allow(non_camel_case_types)]` to fix various issues around it
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
|
|
||||||
## [v0.5.0]
|
## [v0.5.0]
|
||||||
|
|
||||||
TODO!
|
TODO!
|
||||||
|
|
@ -26,56 +27,65 @@ TODO!
|
||||||
## [v0.4.0] - 2020-04-06
|
## [v0.4.0] - 2020-04-06
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
- New supported epds: epd7in5 (thanks to @str4d), epd7in5 v2 (thanks to @asaaki), epd1in54b (thanks to @jkristell)
|
- New supported epds: epd7in5 (thanks to @str4d), epd7in5 v2 (thanks to @asaaki), epd1in54b (thanks to @jkristell)
|
||||||
- Added update_and_display_frame to WaveshareDisplay trait (fixes #38)
|
- Added update_and_display_frame to WaveshareDisplay trait (fixes #38)
|
||||||
- also improve position of busy_wait (#30) once more
|
- also improve position of busy_wait (#30) once more
|
||||||
- More Documenation
|
- More Documentation
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
- Update embedded-graphics to 0.6 (changes Display Trait) (and to 0.5 before thanks to @dbr)
|
- Update embedded-graphics to 0.6 (changes Display Trait) (and to 0.5 before thanks to @dbr)
|
||||||
- Remove useless Featuregates (Doesn't change size)
|
- Remove useless feature gates (Doesn't change size)
|
||||||
- Update and integrate a few important examples and remove the others
|
- Update and integrate a few important examples and remove the others
|
||||||
- Use Embedded_hal:digital::v2
|
- Use Embedded_hal:digital::v2
|
||||||
|
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
- Doc Tests
|
|
||||||
|
|
||||||
|
- Doc Tests
|
||||||
|
|
||||||
## [v0.3.2] - 2019-06-17
|
## [v0.3.2] - 2019-06-17
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
- Added some more missing wait_until_idle calls
|
- Added some more missing wait_until_idle calls
|
||||||
|
|
||||||
## [v0.3.1] - 2019-04-06
|
## [v0.3.1] - 2019-04-06
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
- Example for epd4in2 and BluePill-Board
|
- Example for epd4in2 and BluePill-Board
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
- Improved CI
|
- Improved CI
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
- Timing issues in display_frame function: epd1in54 and epd2in9 were both missing a necessary wait_until_idle call at the end of their display_frame function which sometimes caused invalid/ignored commands/inputs afterwards
|
|
||||||
|
- Timing issues in display_frame function: epd1in54 and epd2in9 were both missing a necessary wait_until_idle call at
|
||||||
|
the end of their display_frame function which sometimes caused invalid/ignored commands/inputs afterwards
|
||||||
- Some CI Targets were not tested correctly before
|
- Some CI Targets were not tested correctly before
|
||||||
|
|
||||||
## [v0.3.0] - 2019-04-04
|
## [v0.3.0] - 2019-04-04
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
- added eink to keywords
|
- added eink to keywords
|
||||||
- added reference to previous crate-name
|
- added reference to previous crate-name
|
||||||
- improved readme/docs e.g. added reference to a few great arduino display libs for these epds
|
- improved readme/docs e.g. added reference to a few great arduino display libs for these epds
|
||||||
- Added is_busy to Waveshare_Interface
|
- Added is_busy to Waveshare_Interface
|
||||||
- Added IS_BUSY_LOW const for all supported epds
|
- Added IS_BUSY_LOW const for all supported epds
|
||||||
- Added is_busy to DisplayInterface
|
- Added is_busy to DisplayInterface
|
||||||
- Added VarDisplay (a variable buffersize display/graphic driver)
|
- Added VarDisplay (a variable buffer-size display/graphic driver)
|
||||||
- Updated and added more examples
|
- Updated and added more examples
|
||||||
- add a feature gated alternative full lut for type_a displays
|
- add a feature gated alternative full lut for type_a displays
|
||||||
|
|
||||||
### Removed
|
### Removed
|
||||||
|
|
||||||
- Removed all Buffers (Buffer1in54,...) and instead made specialised Displays (Display1in54,...) with included Buffers
|
- Removed all Buffers (Buffer1in54,...) and instead made specialised Displays (Display1in54,...) with included Buffers
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
- Switch to 2018 edition
|
- Switch to 2018 edition
|
||||||
- "cargo fix --edition" for the library
|
- "cargo fix --edition" for the library
|
||||||
- Use cargo fix edition-idioms and remove the internal renaming from embedded_hal to hal
|
- Use cargo fix edition-idioms and remove the internal renaming from embedded_hal to hal
|
||||||
|
|
@ -88,19 +98,25 @@ TODO!
|
||||||
Initial release with Changelog
|
Initial release with Changelog
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
- Uses embedded-graphics now
|
- Uses embedded-graphics now
|
||||||
- Tested and fixed 1.54 inch, 2.9 inch and 4.2 inch display
|
- Tested and fixed 1.54 inch, 2.9 inch and 4.2 inch display
|
||||||
|
|
||||||
### Removed
|
### Removed
|
||||||
|
|
||||||
- Old included Graphics Library
|
- Old included Graphics Library
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
- Lots of internal changes
|
- Lots of internal changes
|
||||||
- Renamed to `epd-waveshare`
|
- Renamed to `epd-waveshare`
|
||||||
|
|
||||||
|
|
||||||
[Unreleased]: https://github.com/Caemor/eink-waveshare-rs/compare/v0.4.0...HEAD
|
[Unreleased]: https://github.com/Caemor/eink-waveshare-rs/compare/v0.4.0...HEAD
|
||||||
|
|
||||||
[v0.4.0]: https://github.com/Caemor/eink-waveshare-rs/compare/v0.3.2...v0.4.0
|
[v0.4.0]: https://github.com/Caemor/eink-waveshare-rs/compare/v0.3.2...v0.4.0
|
||||||
|
|
||||||
[v0.3.2]: https://github.com/Caemor/eink-waveshare-rs/compare/v0.3.1...v0.3.2
|
[v0.3.2]: https://github.com/Caemor/eink-waveshare-rs/compare/v0.3.1...v0.3.2
|
||||||
|
|
||||||
[v0.3.1]: https://github.com/Caemor/eink-waveshare-rs/compare/v0.3.0...v0.3.1
|
[v0.3.1]: https://github.com/Caemor/eink-waveshare-rs/compare/v0.3.0...v0.3.1
|
||||||
|
|
||||||
[v0.3.0]: https://github.com/Caemor/eink-waveshare-rs/compare/v0.2.0...v0.3.0
|
[v0.3.0]: https://github.com/Caemor/eink-waveshare-rs/compare/v0.2.0...v0.3.0
|
||||||
|
|
|
||||||
21
README.md
21
README.md
|
|
@ -1,12 +1,14 @@
|
||||||
[](https://travis-ci.com/caemor/epd-waveshare)
|
[](https://travis-ci.com/caemor/epd-waveshare)
|
||||||
|
|
||||||
This library contains a driver for E-Paper Modules from Waveshare (which are basically the same as the Dalian Good Display ones).
|
This library contains a driver for E-Paper Modules from Waveshare (which are basically the same as the Dalian Good
|
||||||
|
Display ones).
|
||||||
|
|
||||||
It uses the [embedded graphics](https://crates.io/crates/embedded-graphics) library for the optional graphics support.
|
It uses the [embedded graphics](https://crates.io/crates/embedded-graphics) library for the optional graphics support.
|
||||||
|
|
||||||
A 2018-edition compatible version (Rust 1.31+) is needed.
|
A 2018-edition compatible version (Rust 1.31+) is needed.
|
||||||
|
|
||||||
Other similiar libraries with support for much more displays are [u8g2](https://github.com/olikraus/u8g2) and [GxEPD](https://github.com/ZinggJM/GxEPD) for arduino.
|
Other similar libraries with support for much more displays are [u8g2](https://github.com/olikraus/u8g2)
|
||||||
|
and [GxEPD](https://github.com/ZinggJM/GxEPD) for arduino.
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
|
||||||
|
|
@ -14,7 +16,7 @@ There are multiple examples in the examples folder. Use `cargo run --example exa
|
||||||
|
|
||||||
```Rust
|
```Rust
|
||||||
// Setup the epd
|
// Setup the epd
|
||||||
let mut epd = EPD4in2::new(&mut spi, cs, busy, dc, rst, &mut delay)?;
|
let mut epd = Epd4in2::new( & mut spi, cs, busy, dc, rst, & mut delay) ?;
|
||||||
|
|
||||||
// Setup the graphics
|
// Setup the graphics
|
||||||
let mut display = Display4in2::default ();
|
let mut display = Display4in2::default ();
|
||||||
|
|
@ -51,11 +53,10 @@ epd.update_and_display_frame(&mut spi, &display.buffer())?;
|
||||||
| [5.65 Inch 7 Color (F)](https://www.waveshare.com/5.65inch-e-paper-module-f.htm) | Black, White, Red, Green, Blue, Yellow, Orange | ✕ | ✕ | ✔ | ✔ |
|
| [5.65 Inch 7 Color (F)](https://www.waveshare.com/5.65inch-e-paper-module-f.htm) | Black, White, Red, Green, Blue, Yellow, Orange | ✕ | ✕ | ✔ | ✔ |
|
||||||
| [2.7 Inch 3 Color (B)](https://www.waveshare.com/2.7inch-e-paper-b.htm) | Black, White, Red | ✕ | ✔ | ✔ | ✔ |
|
| [2.7 Inch 3 Color (B)](https://www.waveshare.com/2.7inch-e-paper-b.htm) | Black, White, Red | ✕ | ✔ | ✔ | ✔ |
|
||||||
|
|
||||||
|
|
||||||
### [1]: 7.5 Inch B/W V2 (A)
|
### [1]: 7.5 Inch B/W V2 (A)
|
||||||
|
|
||||||
Since November 2019 Waveshare sells their updated version of these displays.
|
Since November 2019 Waveshare sells their updated version of these displays. They should have a "V2" marking sticker on
|
||||||
They should have a "V2" marking sticker on the backside of the panel.
|
the backside of the panel.
|
||||||
|
|
||||||
Use `epd7in5_v2` instead of `epd7in5`, because the protocol changed.
|
Use `epd7in5_v2` instead of `epd7in5`, because the protocol changed.
|
||||||
|
|
||||||
|
|
@ -81,10 +82,12 @@ It's possible with this driver but might lead to ghosting / burn-in effects ther
|
||||||
|
|
||||||
### Display Configs
|
### Display Configs
|
||||||
|
|
||||||
There are two types of Display Configurations used in Wavedshare EPDs, which also needs to be set on the "new" E-Paper Driver HAT.
|
There are two types of Display Configurations used in Waveshare EPDs, which also needs to be set on the "new" E-Paper
|
||||||
They are also called A and B, but you shouldn't get confused and mix it with the Type A,B,C and D of the various Displays, which just describe different types (colored variants) or new versions. In the Display Config the seperation is most likely due to included fast partial refresh of the displays. In a Tabular form:
|
Driver HAT. They are also called A and B, but you shouldn't get confused and mix it with the Type A,B,C and D of the
|
||||||
|
various Displays, which just describe different types (colored variants) or new versions. In the Display Config the
|
||||||
|
separation is most likely due to included fast partial refresh of the displays. In a Tabular form:
|
||||||
|
|
||||||
| Type A | Tybe B |
|
| Type A | Type B |
|
||||||
| :---: | :---: |
|
| :---: | :---: |
|
||||||
| 1.54in (A) | 1.54in (B) |
|
| 1.54in (A) | 1.54in (B) |
|
||||||
| 2.13in (A) | 1.54in (C) |
|
| 2.13in (A) | 1.54in (C) |
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#![deny(warnings)]
|
#![deny(warnings)]
|
||||||
|
|
||||||
use embedded_hal::prelude::*;
|
use embedded_hal::prelude::*;
|
||||||
use epd_waveshare::{epd1in54::EPD1in54, prelude::*};
|
use epd_waveshare::{epd1in54::Epd1in54, prelude::*};
|
||||||
use linux_embedded_hal::{
|
use linux_embedded_hal::{
|
||||||
spidev::{self, SpidevOptions},
|
spidev::{self, SpidevOptions},
|
||||||
sysfs_gpio::Direction,
|
sysfs_gpio::Direction,
|
||||||
|
|
@ -58,14 +58,14 @@ fn main() -> Result<(), std::io::Error> {
|
||||||
|
|
||||||
// Setup of the needed pins is finished here
|
// Setup of the needed pins is finished here
|
||||||
// Now the "real" usage of the eink-waveshare-rs crate begins
|
// Now the "real" usage of the eink-waveshare-rs crate begins
|
||||||
let mut epd = EPD1in54::new(&mut spi, cs_pin, busy, dc, rst, &mut delay)?;
|
let mut epd = Epd1in54::new(&mut spi, cs_pin, busy, dc, rst, &mut delay)?;
|
||||||
|
|
||||||
// Clear the full screen
|
// Clear the full screen
|
||||||
epd.clear_frame(&mut spi)?;
|
epd.clear_frame(&mut spi)?;
|
||||||
epd.display_frame(&mut spi)?;
|
epd.display_frame(&mut spi)?;
|
||||||
|
|
||||||
// Speeddemo
|
// Speeddemo
|
||||||
epd.set_lut(&mut spi, Some(RefreshLUT::QUICK))?;
|
epd.set_lut(&mut spi, Some(RefreshLut::Quick))?;
|
||||||
let small_buffer = [Color::Black.get_byte_value(); 32]; //16x16
|
let small_buffer = [Color::Black.get_byte_value(); 32]; //16x16
|
||||||
let number_of_runs = 1;
|
let number_of_runs = 1;
|
||||||
for i in 0..number_of_runs {
|
for i in 0..number_of_runs {
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ use embedded_graphics::{
|
||||||
use embedded_hal::prelude::*;
|
use embedded_hal::prelude::*;
|
||||||
use epd_waveshare::{
|
use epd_waveshare::{
|
||||||
color::*,
|
color::*,
|
||||||
epd2in13_v2::{Display2in13, EPD2in13},
|
epd2in13_v2::{Display2in13, Epd2in13},
|
||||||
graphics::{Display, DisplayRotation},
|
graphics::{Display, DisplayRotation},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
};
|
};
|
||||||
|
|
@ -63,7 +63,7 @@ fn main() -> Result<(), std::io::Error> {
|
||||||
let mut delay = Delay {};
|
let mut delay = Delay {};
|
||||||
|
|
||||||
let mut epd2in13 =
|
let mut epd2in13 =
|
||||||
EPD2in13::new(&mut spi, cs, busy, dc, rst, &mut delay).expect("eink initalize error");
|
Epd2in13::new(&mut spi, cs, busy, dc, rst, &mut delay).expect("eink initalize error");
|
||||||
|
|
||||||
//println!("Test all the rotations");
|
//println!("Test all the rotations");
|
||||||
let mut display = Display2in13::default();
|
let mut display = Display2in13::default();
|
||||||
|
|
@ -121,7 +121,7 @@ fn main() -> Result<(), std::io::Error> {
|
||||||
// Demonstrating how to use the partial refresh feature of the screen.
|
// Demonstrating how to use the partial refresh feature of the screen.
|
||||||
// Real animations can be used.
|
// Real animations can be used.
|
||||||
epd2in13
|
epd2in13
|
||||||
.set_refresh(&mut spi, &mut delay, RefreshLUT::QUICK)
|
.set_refresh(&mut spi, &mut delay, RefreshLut::Quick)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
epd2in13.clear_frame(&mut spi).unwrap();
|
epd2in13.clear_frame(&mut spi).unwrap();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ use embedded_graphics::{
|
||||||
use embedded_hal::prelude::*;
|
use embedded_hal::prelude::*;
|
||||||
use epd_waveshare::{
|
use epd_waveshare::{
|
||||||
color::*,
|
color::*,
|
||||||
epd4in2::{Display4in2, EPD4in2},
|
epd4in2::{Display4in2, Epd4in2},
|
||||||
graphics::{Display, DisplayRotation},
|
graphics::{Display, DisplayRotation},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
};
|
};
|
||||||
|
|
@ -63,7 +63,7 @@ fn main() -> Result<(), std::io::Error> {
|
||||||
let mut delay = Delay {};
|
let mut delay = Delay {};
|
||||||
|
|
||||||
let mut epd4in2 =
|
let mut epd4in2 =
|
||||||
EPD4in2::new(&mut spi, cs, busy, dc, rst, &mut delay).expect("eink initalize error");
|
Epd4in2::new(&mut spi, cs, busy, dc, rst, &mut delay).expect("eink initalize error");
|
||||||
|
|
||||||
//println!("Test all the rotations");
|
//println!("Test all the rotations");
|
||||||
let mut display = Display4in2::default();
|
let mut display = Display4in2::default();
|
||||||
|
|
@ -120,7 +120,7 @@ fn main() -> Result<(), std::io::Error> {
|
||||||
|
|
||||||
// a moving `Hello World!`
|
// a moving `Hello World!`
|
||||||
let limit = 10;
|
let limit = 10;
|
||||||
epd4in2.set_lut(&mut spi, Some(RefreshLUT::QUICK)).unwrap();
|
epd4in2.set_lut(&mut spi, Some(RefreshLut::Quick)).unwrap();
|
||||||
epd4in2.clear_frame(&mut spi).unwrap();
|
epd4in2.clear_frame(&mut spi).unwrap();
|
||||||
for i in 0..limit {
|
for i in 0..limit {
|
||||||
//println!("Moving Hello World. Loop {} from {}", (i + 1), limit);
|
//println!("Moving Hello World. Loop {} from {}", (i + 1), limit);
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ use embedded_graphics::{
|
||||||
use embedded_hal::prelude::*;
|
use embedded_hal::prelude::*;
|
||||||
use epd_waveshare::{
|
use epd_waveshare::{
|
||||||
color::*,
|
color::*,
|
||||||
epd4in2::{self, EPD4in2},
|
epd4in2::{self, Epd4in2},
|
||||||
graphics::{Display, DisplayRotation, VarDisplay},
|
graphics::{Display, DisplayRotation, VarDisplay},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
};
|
};
|
||||||
|
|
@ -64,7 +64,7 @@ fn main() -> Result<(), std::io::Error> {
|
||||||
let mut delay = Delay {};
|
let mut delay = Delay {};
|
||||||
|
|
||||||
let mut epd4in2 =
|
let mut epd4in2 =
|
||||||
EPD4in2::new(&mut spi, cs, busy, dc, rst, &mut delay).expect("eink initalize error");
|
Epd4in2::new(&mut spi, cs, busy, dc, rst, &mut delay).expect("eink initalize error");
|
||||||
|
|
||||||
println!("Test all the rotations");
|
println!("Test all the rotations");
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@
|
||||||
//!# let mut delay = delay::MockNoop::new();
|
//!# let mut delay = delay::MockNoop::new();
|
||||||
//!
|
//!
|
||||||
//!// Setup EPD
|
//!// Setup EPD
|
||||||
//!let mut epd = EPD1in54::new(&mut spi, cs_pin, busy_in, dc, rst, &mut delay)?;
|
//!let mut epd = Epd1in54::new(&mut spi, cs_pin, busy_in, dc, rst, &mut delay)?;
|
||||||
//!
|
//!
|
||||||
//!// Use display graphics from embedded-graphics
|
//!// Use display graphics from embedded-graphics
|
||||||
//!let mut display = Display1in54::default();
|
//!let mut display = Display1in54::default();
|
||||||
|
|
@ -61,7 +61,7 @@ use crate::type_a::{
|
||||||
|
|
||||||
use crate::color::Color;
|
use crate::color::Color;
|
||||||
|
|
||||||
use crate::traits::{RefreshLUT, WaveshareDisplay};
|
use crate::traits::{RefreshLut, WaveshareDisplay};
|
||||||
|
|
||||||
use crate::interface::DisplayInterface;
|
use crate::interface::DisplayInterface;
|
||||||
|
|
||||||
|
|
@ -70,18 +70,18 @@ mod graphics;
|
||||||
#[cfg(feature = "graphics")]
|
#[cfg(feature = "graphics")]
|
||||||
pub use crate::epd1in54::graphics::Display1in54;
|
pub use crate::epd1in54::graphics::Display1in54;
|
||||||
|
|
||||||
/// EPD1in54 driver
|
/// Epd1in54 driver
|
||||||
///
|
///
|
||||||
pub struct EPD1in54<SPI, CS, BUSY, DC, RST> {
|
pub struct Epd1in54<SPI, CS, BUSY, DC, RST> {
|
||||||
/// SPI
|
/// SPI
|
||||||
interface: DisplayInterface<SPI, CS, BUSY, DC, RST>,
|
interface: DisplayInterface<SPI, CS, BUSY, DC, RST>,
|
||||||
/// Color
|
/// Color
|
||||||
background_color: Color,
|
background_color: Color,
|
||||||
/// Refresh LUT
|
/// Refresh LUT
|
||||||
refresh: RefreshLUT,
|
refresh: RefreshLut,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<SPI, CS, BUSY, DC, RST> EPD1in54<SPI, CS, BUSY, DC, RST>
|
impl<SPI, CS, BUSY, DC, RST> Epd1in54<SPI, CS, BUSY, DC, RST>
|
||||||
where
|
where
|
||||||
SPI: Write<u8>,
|
SPI: Write<u8>,
|
||||||
CS: OutputPin,
|
CS: OutputPin,
|
||||||
|
|
@ -103,7 +103,7 @@ where
|
||||||
// Default Values: A = Height of Screen (0x127), B = 0x00 (GD, SM and TB=0?)
|
// Default Values: A = Height of Screen (0x127), B = 0x00 (GD, SM and TB=0?)
|
||||||
self.interface.cmd_with_data(
|
self.interface.cmd_with_data(
|
||||||
spi,
|
spi,
|
||||||
Command::DRIVER_OUTPUT_CONTROL,
|
Command::DriverOutputControl,
|
||||||
&[HEIGHT as u8, (HEIGHT >> 8) as u8, 0x00],
|
&[HEIGHT as u8, (HEIGHT >> 8) as u8, 0x00],
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
|
@ -112,28 +112,25 @@ where
|
||||||
// 1 .. B[6:0] = 0xCE | 0xD6
|
// 1 .. B[6:0] = 0xCE | 0xD6
|
||||||
// 1 .. C[6:0] = 0x8D | 0x9D
|
// 1 .. C[6:0] = 0x8D | 0x9D
|
||||||
//TODO: test
|
//TODO: test
|
||||||
self.interface.cmd_with_data(
|
self.interface
|
||||||
spi,
|
.cmd_with_data(spi, Command::BoosterSoftStartControl, &[0xD7, 0xD6, 0x9D])?;
|
||||||
Command::BOOSTER_SOFT_START_CONTROL,
|
|
||||||
&[0xD7, 0xD6, 0x9D],
|
|
||||||
)?;
|
|
||||||
|
|
||||||
// One Databyte with value 0xA8 for 7V VCOM
|
// One Databyte with value 0xA8 for 7V VCOM
|
||||||
self.interface
|
self.interface
|
||||||
.cmd_with_data(spi, Command::WRITE_VCOM_REGISTER, &[0xA8])?;
|
.cmd_with_data(spi, Command::WriteVcomRegister, &[0xA8])?;
|
||||||
|
|
||||||
// One Databyte with default value 0x1A for 4 dummy lines per gate
|
// One Databyte with default value 0x1A for 4 dummy lines per gate
|
||||||
self.interface
|
self.interface
|
||||||
.cmd_with_data(spi, Command::SET_DUMMY_LINE_PERIOD, &[0x1A])?;
|
.cmd_with_data(spi, Command::SetDummyLinePeriod, &[0x1A])?;
|
||||||
|
|
||||||
// One Databyte with default value 0x08 for 2us per line
|
// One Databyte with default value 0x08 for 2us per line
|
||||||
self.interface
|
self.interface
|
||||||
.cmd_with_data(spi, Command::SET_GATE_LINE_WIDTH, &[0x08])?;
|
.cmd_with_data(spi, Command::SetGateLineWidth, &[0x08])?;
|
||||||
|
|
||||||
// One Databyte with default value 0x03
|
// One Databyte with default value 0x03
|
||||||
// -> address: x increment, y increment, address counter is updated in x direction
|
// -> address: x increment, y increment, address counter is updated in x direction
|
||||||
self.interface
|
self.interface
|
||||||
.cmd_with_data(spi, Command::DATA_ENTRY_MODE_SETTING, &[0x03])?;
|
.cmd_with_data(spi, Command::DataEntryModeSetting, &[0x03])?;
|
||||||
|
|
||||||
self.set_lut(spi, None)?;
|
self.set_lut(spi, None)?;
|
||||||
|
|
||||||
|
|
@ -143,7 +140,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<SPI, CS, BUSY, DC, RST, E> WaveshareDisplay<SPI, CS, BUSY, DC, RST>
|
impl<SPI, CS, BUSY, DC, RST, E> WaveshareDisplay<SPI, CS, BUSY, DC, RST>
|
||||||
for EPD1in54<SPI, CS, BUSY, DC, RST>
|
for Epd1in54<SPI, CS, BUSY, DC, RST>
|
||||||
where
|
where
|
||||||
SPI: Write<u8, Error = E>,
|
SPI: Write<u8, Error = E>,
|
||||||
CS: OutputPin,
|
CS: OutputPin,
|
||||||
|
|
@ -170,10 +167,10 @@ where
|
||||||
) -> Result<Self, SPI::Error> {
|
) -> Result<Self, SPI::Error> {
|
||||||
let interface = DisplayInterface::new(cs, busy, dc, rst);
|
let interface = DisplayInterface::new(cs, busy, dc, rst);
|
||||||
|
|
||||||
let mut epd = EPD1in54 {
|
let mut epd = Epd1in54 {
|
||||||
interface,
|
interface,
|
||||||
background_color: DEFAULT_BACKGROUND_COLOR,
|
background_color: DEFAULT_BACKGROUND_COLOR,
|
||||||
refresh: RefreshLUT::FULL,
|
refresh: RefreshLut::Full,
|
||||||
};
|
};
|
||||||
|
|
||||||
epd.init(spi, delay)?;
|
epd.init(spi, delay)?;
|
||||||
|
|
@ -194,7 +191,7 @@ where
|
||||||
// 0x00 for Normal mode (Power on Reset), 0x01 for Deep Sleep Mode
|
// 0x00 for Normal mode (Power on Reset), 0x01 for Deep Sleep Mode
|
||||||
//TODO: is 0x00 needed here or would 0x01 be even more efficient?
|
//TODO: is 0x00 needed here or would 0x01 be even more efficient?
|
||||||
self.interface
|
self.interface
|
||||||
.cmd_with_data(spi, Command::DEEP_SLEEP_MODE, &[0x00])?;
|
.cmd_with_data(spi, Command::DeepSleepMode, &[0x00])?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -202,7 +199,7 @@ where
|
||||||
self.wait_until_idle();
|
self.wait_until_idle();
|
||||||
self.use_full_frame(spi)?;
|
self.use_full_frame(spi)?;
|
||||||
self.interface
|
self.interface
|
||||||
.cmd_with_data(spi, Command::WRITE_RAM, buffer)?;
|
.cmd_with_data(spi, Command::WriteRam, buffer)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -221,7 +218,7 @@ where
|
||||||
self.set_ram_counter(spi, x, y)?;
|
self.set_ram_counter(spi, x, y)?;
|
||||||
|
|
||||||
self.interface
|
self.interface
|
||||||
.cmd_with_data(spi, Command::WRITE_RAM, buffer)?;
|
.cmd_with_data(spi, Command::WriteRam, buffer)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -230,12 +227,12 @@ where
|
||||||
// enable clock signal, enable cp, display pattern -> 0xC4 (tested with the arduino version)
|
// enable clock signal, enable cp, display pattern -> 0xC4 (tested with the arduino version)
|
||||||
//TODO: test control_1 or control_2 with default value 0xFF (from the datasheet)
|
//TODO: test control_1 or control_2 with default value 0xFF (from the datasheet)
|
||||||
self.interface
|
self.interface
|
||||||
.cmd_with_data(spi, Command::DISPLAY_UPDATE_CONTROL_2, &[0xC4])?;
|
.cmd_with_data(spi, Command::DisplayUpdateControl2, &[0xC4])?;
|
||||||
|
|
||||||
self.interface.cmd(spi, Command::MASTER_ACTIVATION)?;
|
self.interface.cmd(spi, Command::MasterActivation)?;
|
||||||
// MASTER Activation should not be interupted to avoid currption of panel images
|
// MASTER Activation should not be interupted to avoid currption of panel images
|
||||||
// therefore a terminate command is send
|
// therefore a terminate command is send
|
||||||
self.interface.cmd(spi, Command::NOP)?;
|
self.interface.cmd(spi, Command::Nop)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -252,7 +249,7 @@ where
|
||||||
// clear the ram with the background color
|
// clear the ram with the background color
|
||||||
let color = self.background_color.get_byte_value();
|
let color = self.background_color.get_byte_value();
|
||||||
|
|
||||||
self.interface.cmd(spi, Command::WRITE_RAM)?;
|
self.interface.cmd(spi, Command::WriteRam)?;
|
||||||
self.interface
|
self.interface
|
||||||
.data_x_times(spi, color, WIDTH / 8 * HEIGHT)?;
|
.data_x_times(spi, color, WIDTH / 8 * HEIGHT)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
@ -269,14 +266,14 @@ where
|
||||||
fn set_lut(
|
fn set_lut(
|
||||||
&mut self,
|
&mut self,
|
||||||
spi: &mut SPI,
|
spi: &mut SPI,
|
||||||
refresh_rate: Option<RefreshLUT>,
|
refresh_rate: Option<RefreshLut>,
|
||||||
) -> Result<(), SPI::Error> {
|
) -> Result<(), SPI::Error> {
|
||||||
if let Some(refresh_lut) = refresh_rate {
|
if let Some(refresh_lut) = refresh_rate {
|
||||||
self.refresh = refresh_lut;
|
self.refresh = refresh_lut;
|
||||||
}
|
}
|
||||||
match self.refresh {
|
match self.refresh {
|
||||||
RefreshLUT::FULL => self.set_lut_helper(spi, &LUT_FULL_UPDATE),
|
RefreshLut::Full => self.set_lut_helper(spi, &LUT_FULL_UPDATE),
|
||||||
RefreshLUT::QUICK => self.set_lut_helper(spi, &LUT_PARTIAL_UPDATE),
|
RefreshLut::Quick => self.set_lut_helper(spi, &LUT_PARTIAL_UPDATE),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -285,7 +282,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<SPI, CS, BUSY, DC, RST> EPD1in54<SPI, CS, BUSY, DC, RST>
|
impl<SPI, CS, BUSY, DC, RST> Epd1in54<SPI, CS, BUSY, DC, RST>
|
||||||
where
|
where
|
||||||
SPI: Write<u8>,
|
SPI: Write<u8>,
|
||||||
CS: OutputPin,
|
CS: OutputPin,
|
||||||
|
|
@ -321,14 +318,14 @@ where
|
||||||
// aren't relevant
|
// aren't relevant
|
||||||
self.interface.cmd_with_data(
|
self.interface.cmd_with_data(
|
||||||
spi,
|
spi,
|
||||||
Command::SET_RAM_X_ADDRESS_START_END_POSITION,
|
Command::SetRamXAddressStartEndPosition,
|
||||||
&[(start_x >> 3) as u8, (end_x >> 3) as u8],
|
&[(start_x >> 3) as u8, (end_x >> 3) as u8],
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
// 2 Databytes: A[7:0] & 0..A[8] for each - start and end
|
// 2 Databytes: A[7:0] & 0..A[8] for each - start and end
|
||||||
self.interface.cmd_with_data(
|
self.interface.cmd_with_data(
|
||||||
spi,
|
spi,
|
||||||
Command::SET_RAM_Y_ADDRESS_START_END_POSITION,
|
Command::SetRamYAddressStartEndPosition,
|
||||||
&[
|
&[
|
||||||
start_y as u8,
|
start_y as u8,
|
||||||
(start_y >> 8) as u8,
|
(start_y >> 8) as u8,
|
||||||
|
|
@ -349,12 +346,12 @@ where
|
||||||
// x is positioned in bytes, so the last 3 bits which show the position inside a byte in the ram
|
// x is positioned in bytes, so the last 3 bits which show the position inside a byte in the ram
|
||||||
// aren't relevant
|
// aren't relevant
|
||||||
self.interface
|
self.interface
|
||||||
.cmd_with_data(spi, Command::SET_RAM_X_ADDRESS_COUNTER, &[(x >> 3) as u8])?;
|
.cmd_with_data(spi, Command::SetRamXAddressCounter, &[(x >> 3) as u8])?;
|
||||||
|
|
||||||
// 2 Databytes: A[7:0] & 0..A[8]
|
// 2 Databytes: A[7:0] & 0..A[8]
|
||||||
self.interface.cmd_with_data(
|
self.interface.cmd_with_data(
|
||||||
spi,
|
spi,
|
||||||
Command::SET_RAM_Y_ADDRESS_COUNTER,
|
Command::SetRamYAddressCounter,
|
||||||
&[y as u8, (y >> 8) as u8],
|
&[y as u8, (y >> 8) as u8],
|
||||||
)?;
|
)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
@ -365,7 +362,7 @@ where
|
||||||
assert!(buffer.len() == 30);
|
assert!(buffer.len() == 30);
|
||||||
|
|
||||||
self.interface
|
self.interface
|
||||||
.cmd_with_data(spi, Command::WRITE_LUT_REGISTER, buffer)?;
|
.cmd_with_data(spi, Command::WriteLutRegister, buffer)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,35 +2,34 @@
|
||||||
use crate::traits;
|
use crate::traits;
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[allow(non_camel_case_types)]
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
pub(crate) enum Command {
|
pub(crate) enum Command {
|
||||||
PANEL_SETTING = 0x00,
|
PanelSetting = 0x00,
|
||||||
|
|
||||||
POWER_SETTING = 0x01,
|
PowerSetting = 0x01,
|
||||||
POWER_OFF = 0x02,
|
PowerOff = 0x02,
|
||||||
POWER_ON = 0x04,
|
PowerOn = 0x04,
|
||||||
BOOSTER_SOFT_START = 0x06,
|
BoosterSoftStart = 0x06,
|
||||||
DATA_START_TRANSMISSION_1 = 0x10,
|
DataStartTransmission1 = 0x10,
|
||||||
DISPLAY_REFRESH = 0x12,
|
DisplayRefresh = 0x12,
|
||||||
DATA_START_TRANSMISSION_2 = 0x13,
|
DataStartTransmission2 = 0x13,
|
||||||
|
|
||||||
LUT_FOR_VCOM = 0x20,
|
LutForVcom = 0x20,
|
||||||
LUT_WHITE_TO_WHITE = 0x21,
|
LutWhiteToWhite = 0x21,
|
||||||
LUT_BLACK_TO_WHITE = 0x22,
|
LutBlackToWhite = 0x22,
|
||||||
LUT_G0 = 0x23,
|
LutG0 = 0x23,
|
||||||
LUT_G1 = 0x24,
|
LutG1 = 0x24,
|
||||||
LUT_RED_VCOM = 0x25,
|
LutRedVcom = 0x25,
|
||||||
LUT_RED0 = 0x26,
|
LutRed0 = 0x26,
|
||||||
LUT_RED1 = 0x27,
|
LutRed1 = 0x27,
|
||||||
|
|
||||||
PLL_CONTROL = 0x30,
|
PllControl = 0x30,
|
||||||
TEMPERATURE_SENSOR_COMMAND = 0x40,
|
TemperatureSensor = 0x40,
|
||||||
TEMPERATURE_SENSOR_SELECTION = 0x41,
|
TemperatureSensorSelection = 0x41,
|
||||||
VCOM_AND_DATA_INTERVAL_SETTING = 0x50,
|
VcomAndDataIntervalSetting = 0x50,
|
||||||
RESOLUTION_SETTING = 0x61,
|
ResolutionSetting = 0x61,
|
||||||
VCM_DC_SETTING = 0x82,
|
VcmDcSetting = 0x82,
|
||||||
POWER_SAVING = 0xE3,
|
PowerSaving = 0xE3,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl traits::Command for Command {
|
impl traits::Command for Command {
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ use embedded_hal::{
|
||||||
|
|
||||||
use crate::interface::DisplayInterface;
|
use crate::interface::DisplayInterface;
|
||||||
use crate::traits::{
|
use crate::traits::{
|
||||||
InternalWiAdditions, RefreshLUT, WaveshareDisplay, WaveshareThreeColorDisplay,
|
InternalWiAdditions, RefreshLut, WaveshareDisplay, WaveshareThreeColorDisplay,
|
||||||
};
|
};
|
||||||
|
|
||||||
//The Lookup Tables for the Display
|
//The Lookup Tables for the Display
|
||||||
|
|
@ -32,14 +32,14 @@ mod graphics;
|
||||||
#[cfg(feature = "graphics")]
|
#[cfg(feature = "graphics")]
|
||||||
pub use self::graphics::Display1in54b;
|
pub use self::graphics::Display1in54b;
|
||||||
|
|
||||||
/// EPD1in54b driver
|
/// Epd1in54b driver
|
||||||
pub struct EPD1in54b<SPI, CS, BUSY, DC, RST> {
|
pub struct Epd1in54b<SPI, CS, BUSY, DC, RST> {
|
||||||
interface: DisplayInterface<SPI, CS, BUSY, DC, RST>,
|
interface: DisplayInterface<SPI, CS, BUSY, DC, RST>,
|
||||||
color: Color,
|
color: Color,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<SPI, CS, BUSY, DC, RST> InternalWiAdditions<SPI, CS, BUSY, DC, RST>
|
impl<SPI, CS, BUSY, DC, RST> InternalWiAdditions<SPI, CS, BUSY, DC, RST>
|
||||||
for EPD1in54b<SPI, CS, BUSY, DC, RST>
|
for Epd1in54b<SPI, CS, BUSY, DC, RST>
|
||||||
where
|
where
|
||||||
SPI: Write<u8>,
|
SPI: Write<u8>,
|
||||||
CS: OutputPin,
|
CS: OutputPin,
|
||||||
|
|
@ -56,29 +56,29 @@ where
|
||||||
|
|
||||||
// set the power settings
|
// set the power settings
|
||||||
self.interface
|
self.interface
|
||||||
.cmd_with_data(spi, Command::POWER_SETTING, &[0x07, 0x00, 0x08, 0x00])?;
|
.cmd_with_data(spi, Command::PowerSetting, &[0x07, 0x00, 0x08, 0x00])?;
|
||||||
|
|
||||||
// start the booster
|
// start the booster
|
||||||
self.interface
|
self.interface
|
||||||
.cmd_with_data(spi, Command::BOOSTER_SOFT_START, &[0x07, 0x07, 0x07])?;
|
.cmd_with_data(spi, Command::BoosterSoftStart, &[0x07, 0x07, 0x07])?;
|
||||||
|
|
||||||
// power on
|
// power on
|
||||||
self.command(spi, Command::POWER_ON)?;
|
self.command(spi, Command::PowerOn)?;
|
||||||
delay.delay_ms(5);
|
delay.delay_ms(5);
|
||||||
self.wait_until_idle();
|
self.wait_until_idle();
|
||||||
|
|
||||||
// set the panel settings
|
// set the panel settings
|
||||||
self.cmd_with_data(spi, Command::PANEL_SETTING, &[0xCF])?;
|
self.cmd_with_data(spi, Command::PanelSetting, &[0xCF])?;
|
||||||
|
|
||||||
self.cmd_with_data(spi, Command::VCOM_AND_DATA_INTERVAL_SETTING, &[0x37])?;
|
self.cmd_with_data(spi, Command::VcomAndDataIntervalSetting, &[0x37])?;
|
||||||
|
|
||||||
// PLL
|
// PLL
|
||||||
self.cmd_with_data(spi, Command::PLL_CONTROL, &[0x39])?;
|
self.cmd_with_data(spi, Command::PllControl, &[0x39])?;
|
||||||
|
|
||||||
// set resolution
|
// set resolution
|
||||||
self.send_resolution(spi)?;
|
self.send_resolution(spi)?;
|
||||||
|
|
||||||
self.cmd_with_data(spi, Command::VCM_DC_SETTING, &[0x0E])?;
|
self.cmd_with_data(spi, Command::VcmDcSetting, &[0x0E])?;
|
||||||
|
|
||||||
self.set_lut(spi, None)?;
|
self.set_lut(spi, None)?;
|
||||||
|
|
||||||
|
|
@ -89,7 +89,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<SPI, CS, BUSY, DC, RST> WaveshareThreeColorDisplay<SPI, CS, BUSY, DC, RST>
|
impl<SPI, CS, BUSY, DC, RST> WaveshareThreeColorDisplay<SPI, CS, BUSY, DC, RST>
|
||||||
for EPD1in54b<SPI, CS, BUSY, DC, RST>
|
for Epd1in54b<SPI, CS, BUSY, DC, RST>
|
||||||
where
|
where
|
||||||
SPI: Write<u8>,
|
SPI: Write<u8>,
|
||||||
CS: OutputPin,
|
CS: OutputPin,
|
||||||
|
|
@ -111,8 +111,7 @@ where
|
||||||
self.wait_until_idle();
|
self.wait_until_idle();
|
||||||
self.send_resolution(spi)?;
|
self.send_resolution(spi)?;
|
||||||
|
|
||||||
self.interface
|
self.interface.cmd(spi, Command::DataStartTransmission1)?;
|
||||||
.cmd(spi, Command::DATA_START_TRANSMISSION_1)?;
|
|
||||||
|
|
||||||
for b in black {
|
for b in black {
|
||||||
let expanded = expand_bits(*b);
|
let expanded = expand_bits(*b);
|
||||||
|
|
@ -126,15 +125,14 @@ where
|
||||||
spi: &mut SPI,
|
spi: &mut SPI,
|
||||||
chromatic: &[u8],
|
chromatic: &[u8],
|
||||||
) -> Result<(), SPI::Error> {
|
) -> Result<(), SPI::Error> {
|
||||||
self.interface
|
self.interface.cmd(spi, Command::DataStartTransmission2)?;
|
||||||
.cmd(spi, Command::DATA_START_TRANSMISSION_2)?;
|
|
||||||
self.interface.data(spi, chromatic)?;
|
self.interface.data(spi, chromatic)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<SPI, CS, BUSY, DC, RST> WaveshareDisplay<SPI, CS, BUSY, DC, RST>
|
impl<SPI, CS, BUSY, DC, RST> WaveshareDisplay<SPI, CS, BUSY, DC, RST>
|
||||||
for EPD1in54b<SPI, CS, BUSY, DC, RST>
|
for Epd1in54b<SPI, CS, BUSY, DC, RST>
|
||||||
where
|
where
|
||||||
SPI: Write<u8>,
|
SPI: Write<u8>,
|
||||||
CS: OutputPin,
|
CS: OutputPin,
|
||||||
|
|
@ -154,7 +152,7 @@ where
|
||||||
let interface = DisplayInterface::new(cs, busy, dc, rst);
|
let interface = DisplayInterface::new(cs, busy, dc, rst);
|
||||||
let color = DEFAULT_BACKGROUND_COLOR;
|
let color = DEFAULT_BACKGROUND_COLOR;
|
||||||
|
|
||||||
let mut epd = EPD1in54b { interface, color };
|
let mut epd = Epd1in54b { interface, color };
|
||||||
|
|
||||||
epd.init(spi, delay)?;
|
epd.init(spi, delay)?;
|
||||||
|
|
||||||
|
|
@ -164,19 +162,19 @@ where
|
||||||
fn sleep(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> {
|
fn sleep(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> {
|
||||||
self.wait_until_idle();
|
self.wait_until_idle();
|
||||||
self.interface
|
self.interface
|
||||||
.cmd_with_data(spi, Command::VCOM_AND_DATA_INTERVAL_SETTING, &[0x17])?; //border floating
|
.cmd_with_data(spi, Command::VcomAndDataIntervalSetting, &[0x17])?; //border floating
|
||||||
|
|
||||||
self.interface
|
self.interface
|
||||||
.cmd_with_data(spi, Command::VCM_DC_SETTING, &[0x00])?; // VCOM to 0V
|
.cmd_with_data(spi, Command::VcmDcSetting, &[0x00])?; // Vcom to 0V
|
||||||
|
|
||||||
self.interface
|
self.interface
|
||||||
.cmd_with_data(spi, Command::POWER_SETTING, &[0x02, 0x00, 0x00, 0x00])?; //VG&VS to 0V fast
|
.cmd_with_data(spi, Command::PowerSetting, &[0x02, 0x00, 0x00, 0x00])?; //VG&VS to 0V fast
|
||||||
|
|
||||||
self.wait_until_idle();
|
self.wait_until_idle();
|
||||||
|
|
||||||
//NOTE: The example code has a 1s delay here
|
//NOTE: The example code has a 1s delay here
|
||||||
|
|
||||||
self.command(spi, Command::POWER_OFF)?;
|
self.command(spi, Command::PowerOff)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
@ -209,8 +207,7 @@ where
|
||||||
self.wait_until_idle();
|
self.wait_until_idle();
|
||||||
self.send_resolution(spi)?;
|
self.send_resolution(spi)?;
|
||||||
|
|
||||||
self.interface
|
self.interface.cmd(spi, Command::DataStartTransmission1)?;
|
||||||
.cmd(spi, Command::DATA_START_TRANSMISSION_1)?;
|
|
||||||
|
|
||||||
for b in buffer {
|
for b in buffer {
|
||||||
// Two bits per pixel
|
// Two bits per pixel
|
||||||
|
|
@ -224,8 +221,7 @@ where
|
||||||
let color = self.color.get_byte_value();
|
let color = self.color.get_byte_value();
|
||||||
let nbits = WIDTH * (HEIGHT / 8);
|
let nbits = WIDTH * (HEIGHT / 8);
|
||||||
|
|
||||||
self.interface
|
self.interface.cmd(spi, Command::DataStartTransmission2)?;
|
||||||
.cmd(spi, Command::DATA_START_TRANSMISSION_2)?;
|
|
||||||
self.interface.data_x_times(spi, color, nbits)?;
|
self.interface.data_x_times(spi, color, nbits)?;
|
||||||
|
|
||||||
//NOTE: Example code has a delay here
|
//NOTE: Example code has a delay here
|
||||||
|
|
@ -247,7 +243,7 @@ where
|
||||||
|
|
||||||
fn display_frame(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> {
|
fn display_frame(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> {
|
||||||
self.wait_until_idle();
|
self.wait_until_idle();
|
||||||
self.command(spi, Command::DISPLAY_REFRESH)?;
|
self.command(spi, Command::DisplayRefresh)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -264,16 +260,14 @@ where
|
||||||
let color = DEFAULT_BACKGROUND_COLOR.get_byte_value();
|
let color = DEFAULT_BACKGROUND_COLOR.get_byte_value();
|
||||||
|
|
||||||
// Clear the black
|
// Clear the black
|
||||||
self.interface
|
self.interface.cmd(spi, Command::DataStartTransmission1)?;
|
||||||
.cmd(spi, Command::DATA_START_TRANSMISSION_1)?;
|
|
||||||
|
|
||||||
// Uses 2 bits per pixel
|
// Uses 2 bits per pixel
|
||||||
self.interface
|
self.interface
|
||||||
.data_x_times(spi, color, 2 * (WIDTH * HEIGHT / 8))?;
|
.data_x_times(spi, color, 2 * (WIDTH * HEIGHT / 8))?;
|
||||||
|
|
||||||
// Clear the red
|
// Clear the red
|
||||||
self.interface
|
self.interface.cmd(spi, Command::DataStartTransmission2)?;
|
||||||
.cmd(spi, Command::DATA_START_TRANSMISSION_2)?;
|
|
||||||
self.interface
|
self.interface
|
||||||
.data_x_times(spi, color, WIDTH * HEIGHT / 8)?;
|
.data_x_times(spi, color, WIDTH * HEIGHT / 8)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
@ -282,22 +276,22 @@ where
|
||||||
fn set_lut(
|
fn set_lut(
|
||||||
&mut self,
|
&mut self,
|
||||||
spi: &mut SPI,
|
spi: &mut SPI,
|
||||||
_refresh_rate: Option<RefreshLUT>,
|
_refresh_rate: Option<RefreshLut>,
|
||||||
) -> Result<(), SPI::Error> {
|
) -> Result<(), SPI::Error> {
|
||||||
self.interface
|
self.interface
|
||||||
.cmd_with_data(spi, Command::LUT_FOR_VCOM, LUT_VCOM0)?;
|
.cmd_with_data(spi, Command::LutForVcom, LUT_VCOM0)?;
|
||||||
self.interface
|
self.interface
|
||||||
.cmd_with_data(spi, Command::LUT_WHITE_TO_WHITE, LUT_WHITE_TO_WHITE)?;
|
.cmd_with_data(spi, Command::LutWhiteToWhite, LUT_WHITE_TO_WHITE)?;
|
||||||
self.interface
|
self.interface
|
||||||
.cmd_with_data(spi, Command::LUT_BLACK_TO_WHITE, LUT_BLACK_TO_WHITE)?;
|
.cmd_with_data(spi, Command::LutBlackToWhite, LUT_BLACK_TO_WHITE)?;
|
||||||
self.interface.cmd_with_data(spi, Command::LUT_G0, LUT_G1)?;
|
self.interface.cmd_with_data(spi, Command::LutG0, LUT_G1)?;
|
||||||
self.interface.cmd_with_data(spi, Command::LUT_G1, LUT_G2)?;
|
self.interface.cmd_with_data(spi, Command::LutG1, LUT_G2)?;
|
||||||
self.interface
|
self.interface
|
||||||
.cmd_with_data(spi, Command::LUT_RED_VCOM, LUT_RED_VCOM)?;
|
.cmd_with_data(spi, Command::LutRedVcom, LUT_RED_VCOM)?;
|
||||||
self.interface
|
self.interface
|
||||||
.cmd_with_data(spi, Command::LUT_RED0, LUT_RED0)?;
|
.cmd_with_data(spi, Command::LutRed0, LUT_RED0)?;
|
||||||
self.interface
|
self.interface
|
||||||
.cmd_with_data(spi, Command::LUT_RED1, LUT_RED1)?;
|
.cmd_with_data(spi, Command::LutRed1, LUT_RED1)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
@ -307,7 +301,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<SPI, CS, BUSY, DC, RST> EPD1in54b<SPI, CS, BUSY, DC, RST>
|
impl<SPI, CS, BUSY, DC, RST> Epd1in54b<SPI, CS, BUSY, DC, RST>
|
||||||
where
|
where
|
||||||
SPI: Write<u8>,
|
SPI: Write<u8>,
|
||||||
CS: OutputPin,
|
CS: OutputPin,
|
||||||
|
|
@ -340,7 +334,7 @@ where
|
||||||
let w = self.width();
|
let w = self.width();
|
||||||
let h = self.height();
|
let h = self.height();
|
||||||
|
|
||||||
self.command(spi, Command::RESOLUTION_SETTING)?;
|
self.command(spi, Command::ResolutionSetting)?;
|
||||||
|
|
||||||
self.send_data(spi, &[w as u8])?;
|
self.send_data(spi, &[w as u8])?;
|
||||||
self.send_data(spi, &[(h >> 8) as u8])?;
|
self.send_data(spi, &[(h >> 8) as u8])?;
|
||||||
|
|
|
||||||
|
|
@ -2,33 +2,32 @@
|
||||||
use crate::traits;
|
use crate::traits;
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[allow(non_camel_case_types)]
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
pub(crate) enum Command {
|
pub(crate) enum Command {
|
||||||
PANEL_SETTING = 0x00,
|
PanelSetting = 0x00,
|
||||||
|
|
||||||
POWER_SETTING = 0x01,
|
PowerSetting = 0x01,
|
||||||
POWER_OFF = 0x02,
|
PowerOff = 0x02,
|
||||||
POWER_ON = 0x04,
|
PowerOn = 0x04,
|
||||||
BOOSTER_SOFT_START = 0x06,
|
BoosterSoftStart = 0x06,
|
||||||
DEEP_SLEEP = 0x07,
|
DeepSleep = 0x07,
|
||||||
DATA_START_TRANSMISSION_1 = 0x10,
|
DataStartTransmission1 = 0x10,
|
||||||
DISPLAY_REFRESH = 0x12,
|
DisplayRefresh = 0x12,
|
||||||
DATA_START_TRANSMISSION_2 = 0x13,
|
DataStartTransmission2 = 0x13,
|
||||||
|
|
||||||
LUT_FOR_VCOM = 0x20,
|
LutForVcom = 0x20,
|
||||||
LUT_WHITE_TO_WHITE = 0x21,
|
LutWhiteToWhite = 0x21,
|
||||||
LUT_BLACK_TO_WHITE = 0x22,
|
LutBlackToWhite = 0x22,
|
||||||
LUT_WHITE_TO_BLACK = 0x23,
|
LutWhiteToBlack = 0x23,
|
||||||
LUT_BLACK_TO_BLACK = 0x24,
|
LutBlackToBlack = 0x24,
|
||||||
|
|
||||||
PLL_CONTROL = 0x30,
|
PllControl = 0x30,
|
||||||
TEMPERATURE_SENSOR_COMMAND = 0x40,
|
TemperatureSensor = 0x40,
|
||||||
TEMPERATURE_SENSOR_SELECTION = 0x41,
|
TemperatureSensorSelection = 0x41,
|
||||||
VCOM_AND_DATA_INTERVAL_SETTING = 0x50,
|
VcomAndDataIntervalSetting = 0x50,
|
||||||
RESOLUTION_SETTING = 0x61,
|
ResolutionSetting = 0x61,
|
||||||
VCM_DC_SETTING = 0x82,
|
VcmDcSetting = 0x82,
|
||||||
POWER_SAVING = 0xE3,
|
PowerSaving = 0xE3,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl traits::Command for Command {
|
impl traits::Command for Command {
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ use embedded_hal::{
|
||||||
|
|
||||||
use crate::interface::DisplayInterface;
|
use crate::interface::DisplayInterface;
|
||||||
use crate::traits::{
|
use crate::traits::{
|
||||||
InternalWiAdditions, RefreshLUT, WaveshareDisplay, WaveshareThreeColorDisplay,
|
InternalWiAdditions, RefreshLut, WaveshareDisplay, WaveshareThreeColorDisplay,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Width of epd1in54 in pixels
|
/// Width of epd1in54 in pixels
|
||||||
|
|
@ -30,14 +30,14 @@ mod graphics;
|
||||||
#[cfg(feature = "graphics")]
|
#[cfg(feature = "graphics")]
|
||||||
pub use self::graphics::Display1in54c;
|
pub use self::graphics::Display1in54c;
|
||||||
|
|
||||||
/// EPD1in54c driver
|
/// Epd1in54c driver
|
||||||
pub struct EPD1in54c<SPI, CS, BUSY, DC, RST> {
|
pub struct Epd1in54c<SPI, CS, BUSY, DC, RST> {
|
||||||
interface: DisplayInterface<SPI, CS, BUSY, DC, RST>,
|
interface: DisplayInterface<SPI, CS, BUSY, DC, RST>,
|
||||||
color: Color,
|
color: Color,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<SPI, CS, BUSY, DC, RST> InternalWiAdditions<SPI, CS, BUSY, DC, RST>
|
impl<SPI, CS, BUSY, DC, RST> InternalWiAdditions<SPI, CS, BUSY, DC, RST>
|
||||||
for EPD1in54c<SPI, CS, BUSY, DC, RST>
|
for Epd1in54c<SPI, CS, BUSY, DC, RST>
|
||||||
where
|
where
|
||||||
SPI: Write<u8>,
|
SPI: Write<u8>,
|
||||||
CS: OutputPin,
|
CS: OutputPin,
|
||||||
|
|
@ -57,27 +57,27 @@ where
|
||||||
self.interface.reset(delay, 2);
|
self.interface.reset(delay, 2);
|
||||||
|
|
||||||
// start the booster
|
// start the booster
|
||||||
self.cmd_with_data(spi, Command::BOOSTER_SOFT_START, &[0x17, 0x17, 0x17])?;
|
self.cmd_with_data(spi, Command::BoosterSoftStart, &[0x17, 0x17, 0x17])?;
|
||||||
|
|
||||||
// power on
|
// power on
|
||||||
self.command(spi, Command::POWER_ON)?;
|
self.command(spi, Command::PowerOn)?;
|
||||||
delay.delay_ms(5);
|
delay.delay_ms(5);
|
||||||
self.wait_until_idle();
|
self.wait_until_idle();
|
||||||
|
|
||||||
// set the panel settings
|
// set the panel settings
|
||||||
self.cmd_with_data(spi, Command::PANEL_SETTING, &[0x0f, 0x0d])?;
|
self.cmd_with_data(spi, Command::PanelSetting, &[0x0f, 0x0d])?;
|
||||||
|
|
||||||
// set resolution
|
// set resolution
|
||||||
self.send_resolution(spi)?;
|
self.send_resolution(spi)?;
|
||||||
|
|
||||||
self.cmd_with_data(spi, Command::VCOM_AND_DATA_INTERVAL_SETTING, &[0x77])?;
|
self.cmd_with_data(spi, Command::VcomAndDataIntervalSetting, &[0x77])?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<SPI, CS, BUSY, DC, RST> WaveshareThreeColorDisplay<SPI, CS, BUSY, DC, RST>
|
impl<SPI, CS, BUSY, DC, RST> WaveshareThreeColorDisplay<SPI, CS, BUSY, DC, RST>
|
||||||
for EPD1in54c<SPI, CS, BUSY, DC, RST>
|
for Epd1in54c<SPI, CS, BUSY, DC, RST>
|
||||||
where
|
where
|
||||||
SPI: Write<u8>,
|
SPI: Write<u8>,
|
||||||
CS: OutputPin,
|
CS: OutputPin,
|
||||||
|
|
@ -97,7 +97,7 @@ where
|
||||||
|
|
||||||
fn update_achromatic_frame(&mut self, spi: &mut SPI, black: &[u8]) -> Result<(), SPI::Error> {
|
fn update_achromatic_frame(&mut self, spi: &mut SPI, black: &[u8]) -> Result<(), SPI::Error> {
|
||||||
self.wait_until_idle();
|
self.wait_until_idle();
|
||||||
self.cmd_with_data(spi, Command::DATA_START_TRANSMISSION_1, black)?;
|
self.cmd_with_data(spi, Command::DataStartTransmission1, black)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
@ -108,14 +108,14 @@ where
|
||||||
chromatic: &[u8],
|
chromatic: &[u8],
|
||||||
) -> Result<(), SPI::Error> {
|
) -> Result<(), SPI::Error> {
|
||||||
self.wait_until_idle();
|
self.wait_until_idle();
|
||||||
self.cmd_with_data(spi, Command::DATA_START_TRANSMISSION_2, chromatic)?;
|
self.cmd_with_data(spi, Command::DataStartTransmission2, chromatic)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<SPI, CS, BUSY, DC, RST> WaveshareDisplay<SPI, CS, BUSY, DC, RST>
|
impl<SPI, CS, BUSY, DC, RST> WaveshareDisplay<SPI, CS, BUSY, DC, RST>
|
||||||
for EPD1in54c<SPI, CS, BUSY, DC, RST>
|
for Epd1in54c<SPI, CS, BUSY, DC, RST>
|
||||||
where
|
where
|
||||||
SPI: Write<u8>,
|
SPI: Write<u8>,
|
||||||
CS: OutputPin,
|
CS: OutputPin,
|
||||||
|
|
@ -135,7 +135,7 @@ where
|
||||||
let interface = DisplayInterface::new(cs, busy, dc, rst);
|
let interface = DisplayInterface::new(cs, busy, dc, rst);
|
||||||
let color = DEFAULT_BACKGROUND_COLOR;
|
let color = DEFAULT_BACKGROUND_COLOR;
|
||||||
|
|
||||||
let mut epd = EPD1in54c { interface, color };
|
let mut epd = Epd1in54c { interface, color };
|
||||||
|
|
||||||
epd.init(spi, delay)?;
|
epd.init(spi, delay)?;
|
||||||
|
|
||||||
|
|
@ -145,9 +145,9 @@ where
|
||||||
fn sleep(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> {
|
fn sleep(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> {
|
||||||
self.wait_until_idle();
|
self.wait_until_idle();
|
||||||
|
|
||||||
self.command(spi, Command::POWER_OFF)?;
|
self.command(spi, Command::PowerOff)?;
|
||||||
self.wait_until_idle();
|
self.wait_until_idle();
|
||||||
self.cmd_with_data(spi, Command::DEEP_SLEEP, &[0xa5])?;
|
self.cmd_with_data(spi, Command::DeepSleep, &[0xa5])?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
@ -182,7 +182,7 @@ where
|
||||||
// Clear the chromatic layer
|
// Clear the chromatic layer
|
||||||
let color = self.color.get_byte_value();
|
let color = self.color.get_byte_value();
|
||||||
|
|
||||||
self.command(spi, Command::DATA_START_TRANSMISSION_2)?;
|
self.command(spi, Command::DataStartTransmission2)?;
|
||||||
self.interface.data_x_times(spi, color, NUM_DISPLAY_BITS)?;
|
self.interface.data_x_times(spi, color, NUM_DISPLAY_BITS)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
@ -202,7 +202,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
fn display_frame(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> {
|
fn display_frame(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> {
|
||||||
self.command(spi, Command::DISPLAY_REFRESH)?;
|
self.command(spi, Command::DisplayRefresh)?;
|
||||||
self.wait_until_idle();
|
self.wait_until_idle();
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
@ -220,11 +220,11 @@ where
|
||||||
let color = DEFAULT_BACKGROUND_COLOR.get_byte_value();
|
let color = DEFAULT_BACKGROUND_COLOR.get_byte_value();
|
||||||
|
|
||||||
// Clear the black
|
// Clear the black
|
||||||
self.command(spi, Command::DATA_START_TRANSMISSION_1)?;
|
self.command(spi, Command::DataStartTransmission1)?;
|
||||||
self.interface.data_x_times(spi, color, NUM_DISPLAY_BITS)?;
|
self.interface.data_x_times(spi, color, NUM_DISPLAY_BITS)?;
|
||||||
|
|
||||||
// Clear the chromatic
|
// Clear the chromatic
|
||||||
self.command(spi, Command::DATA_START_TRANSMISSION_2)?;
|
self.command(spi, Command::DataStartTransmission2)?;
|
||||||
self.interface.data_x_times(spi, color, NUM_DISPLAY_BITS)?;
|
self.interface.data_x_times(spi, color, NUM_DISPLAY_BITS)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
@ -233,7 +233,7 @@ where
|
||||||
fn set_lut(
|
fn set_lut(
|
||||||
&mut self,
|
&mut self,
|
||||||
_spi: &mut SPI,
|
_spi: &mut SPI,
|
||||||
_refresh_rate: Option<RefreshLUT>,
|
_refresh_rate: Option<RefreshLut>,
|
||||||
) -> Result<(), SPI::Error> {
|
) -> Result<(), SPI::Error> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
@ -243,7 +243,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<SPI, CS, BUSY, DC, RST> EPD1in54c<SPI, CS, BUSY, DC, RST>
|
impl<SPI, CS, BUSY, DC, RST> Epd1in54c<SPI, CS, BUSY, DC, RST>
|
||||||
where
|
where
|
||||||
SPI: Write<u8>,
|
SPI: Write<u8>,
|
||||||
CS: OutputPin,
|
CS: OutputPin,
|
||||||
|
|
@ -276,7 +276,7 @@ where
|
||||||
let w = self.width();
|
let w = self.width();
|
||||||
let h = self.height();
|
let h = self.height();
|
||||||
|
|
||||||
self.command(spi, Command::RESOLUTION_SETTING)?;
|
self.command(spi, Command::ResolutionSetting)?;
|
||||||
|
|
||||||
// | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
|
// | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
|
||||||
// | HRES[7:3] | 0 | 0 | 0 |
|
// | HRES[7:3] | 0 | 0 | 0 |
|
||||||
|
|
|
||||||
|
|
@ -5,57 +5,56 @@ use crate::traits;
|
||||||
extern crate bit_field;
|
extern crate bit_field;
|
||||||
use bit_field::BitField;
|
use bit_field::BitField;
|
||||||
|
|
||||||
/// EPD2in13 v2
|
/// Epd2in13 v2
|
||||||
///
|
///
|
||||||
/// For more infos about the addresses and what they are doing look into the pdfs
|
/// For more infos about the addresses and what they are doing look into the pdfs
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[allow(non_camel_case_types)]
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
pub(crate) enum Command {
|
pub(crate) enum Command {
|
||||||
DRIVER_OUTPUT_CONTROL = 0x01,
|
DriverOutputControl = 0x01,
|
||||||
GATE_DRIVING_VOLTAGE_CTRL = 0x03,
|
GateDrivingVoltageCtrl = 0x03,
|
||||||
SOURCE_DRIVING_VOLTAGE_CTRL = 0x04,
|
SourceDrivingVoltageCtrl = 0x04,
|
||||||
BOOSTER_SOFT_START_CONTROL = 0x0C,
|
BoosterSoftStartControl = 0x0C,
|
||||||
GATE_SCAN_START_POSITION = 0x0F,
|
GateScanStartPosition = 0x0F,
|
||||||
DEEP_SLEEP_MODE = 0x10,
|
DeepSleepMode = 0x10,
|
||||||
DATA_ENTRY_MODE_SETTING = 0x11,
|
DataEntryModeSetting = 0x11,
|
||||||
SW_RESET = 0x12,
|
SwReset = 0x12,
|
||||||
HV_READY_DETECTION = 0x14,
|
HvReadyDetection = 0x14,
|
||||||
VCI_DETECTION = 0x15,
|
VciDetection = 0x15,
|
||||||
TEMPERATURE_SENSOR_CONTROL_WRITE = 0x1A,
|
TemperatureSensorControlWrite = 0x1A,
|
||||||
TEMPERATURE_SENSOR_CONTROL_READ = 0x1B,
|
TemperatureSensorControlRead = 0x1B,
|
||||||
TEMPERATURE_SENSOR_EXT_CONTROL_WRITE = 0x1C,
|
TemperatureSensorExtControlWrite = 0x1C,
|
||||||
MASTER_ACTIVATION = 0x20,
|
MasterActivation = 0x20,
|
||||||
DISPLAY_UPDATE_CONTROL_1 = 0x21,
|
DisplayUpdateControl1 = 0x21,
|
||||||
DISPLAY_UPDATE_CONTROL_2 = 0x22,
|
DisplayUpdateControl2 = 0x22,
|
||||||
WRITE_RAM = 0x24,
|
WriteRam = 0x24,
|
||||||
WRITE_RAM_RED = 0x26,
|
WriteRamRed = 0x26,
|
||||||
READ_RAM = 0x27,
|
ReadRam = 0x27,
|
||||||
VCOM_SENSE = 0x28,
|
VcomSense = 0x28,
|
||||||
VCOM_SENSE_DURATION = 0x29,
|
VcomSenseDuration = 0x29,
|
||||||
PROGRAM_VCOM_OPT = 0x2A,
|
ProgramVcomOpt = 0x2A,
|
||||||
WRITE_VCOM_REGISTER = 0x2C,
|
WriteVcomRegister = 0x2C,
|
||||||
OTP_REGISTER_READ = 0x2D,
|
OtpRegisterRead = 0x2D,
|
||||||
STATUS_BIT_READ = 0x2F,
|
StatusBitRead = 0x2F,
|
||||||
PROGRAM_WS_OTP = 0x30,
|
ProgramWsOtp = 0x30,
|
||||||
LOAD_WS_OTP = 0x31,
|
LoadWsOtp = 0x31,
|
||||||
WRITE_LUT_REGISTER = 0x32,
|
WriteLutRegister = 0x32,
|
||||||
PROGRAM_OTP_SELECTION = 0x36,
|
ProgramOtpSelection = 0x36,
|
||||||
WRITE_OTP_SELECTION = 0x37,
|
WriteOtpSelection = 0x37,
|
||||||
SET_DUMMY_LINE_PERIOD = 0x3A,
|
SetDummyLinePeriod = 0x3A,
|
||||||
SET_GATE_LINE_WIDTH = 0x3B,
|
SetGateLineWidth = 0x3B,
|
||||||
BORDER_WAVEFORM_CONTROL = 0x3C,
|
BorderWaveformControl = 0x3C,
|
||||||
READ_RAM_OPTION = 0x41,
|
ReadRamOption = 0x41,
|
||||||
SET_RAM_X_ADDRESS_START_END_POSITION = 0x44,
|
SetRamXAddressStartEndPosition = 0x44,
|
||||||
SET_RAM_Y_ADDRESS_START_END_POSITION = 0x45,
|
SetRamYAddressStartEndPosition = 0x45,
|
||||||
AUTO_WRITE_RED_RAM_REGULAR_PATTERN = 0x46,
|
AutoWriteRedRamRegularPattern = 0x46,
|
||||||
AUTO_WRITE_BW_RAM_REGULAR_PATTERN = 0x47,
|
AutoWriteBwRamRegularPattern = 0x47,
|
||||||
SET_RAM_X_ADDRESS_COUNTER = 0x4E,
|
SetRamXAddressCounter = 0x4E,
|
||||||
SET_RAM_Y_ADDRESS_COUNTER = 0x4F,
|
SetRamYAddressCounter = 0x4F,
|
||||||
SET_ANALOG_BLOCK_CONTROL = 0x74,
|
SetAnalogBlockControl = 0x74,
|
||||||
SET_DIGITAL_BLOCK_CONTROL = 0x7E,
|
SetDigitalBlockControl = 0x7E,
|
||||||
|
|
||||||
NOP = 0x7F,
|
Nop = 0x7F,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct DriverOutput {
|
pub(crate) struct DriverOutput {
|
||||||
|
|
@ -135,54 +134,51 @@ impl DisplayUpdateControl2 {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[allow(non_camel_case_types)]
|
|
||||||
pub(crate) enum DataEntryModeIncr {
|
pub(crate) enum DataEntryModeIncr {
|
||||||
X_DECR_Y_DECR = 0x0,
|
XDecrYDecr = 0x0,
|
||||||
X_INCR_Y_DECR = 0x1,
|
XIncrYDecr = 0x1,
|
||||||
X_DECR_Y_INCR = 0x2,
|
XDecrYIncr = 0x2,
|
||||||
X_INCR_Y_INCR = 0x3,
|
XIncrYIncr = 0x3,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[allow(non_camel_case_types)]
|
|
||||||
pub(crate) enum DataEntryModeDir {
|
pub(crate) enum DataEntryModeDir {
|
||||||
X_DIR = 0x0,
|
XDir = 0x0,
|
||||||
Y_DIR = 0x4,
|
YDir = 0x4,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[allow(non_camel_case_types)]
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
pub(crate) enum BorderWaveFormVBD {
|
pub(crate) enum BorderWaveFormVbd {
|
||||||
GS = 0x0,
|
Gs = 0x0,
|
||||||
FIX_LEVEL = 0x1,
|
FixLevel = 0x1,
|
||||||
VCOM = 0x2,
|
Vcom = 0x2,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[allow(non_camel_case_types)]
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
pub(crate) enum BorderWaveFormFixLevel {
|
pub(crate) enum BorderWaveFormFixLevel {
|
||||||
VSS = 0x0,
|
Vss = 0x0,
|
||||||
VSH1 = 0x1,
|
Vsh1 = 0x1,
|
||||||
VSL = 0x2,
|
Vsl = 0x2,
|
||||||
VSH2 = 0x3,
|
Vsh2 = 0x3,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[allow(non_camel_case_types)]
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
pub(crate) enum BorderWaveFormGS {
|
pub(crate) enum BorderWaveFormGs {
|
||||||
LUT0 = 0x0,
|
Lut0 = 0x0,
|
||||||
LUT1 = 0x1,
|
Lut1 = 0x1,
|
||||||
LUT2 = 0x2,
|
Lut2 = 0x2,
|
||||||
LUT3 = 0x3,
|
Lut3 = 0x3,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct BorderWaveForm {
|
pub(crate) struct BorderWaveForm {
|
||||||
pub vbd: BorderWaveFormVBD,
|
pub vbd: BorderWaveFormVbd,
|
||||||
pub fix_level: BorderWaveFormFixLevel,
|
pub fix_level: BorderWaveFormFixLevel,
|
||||||
pub gs_trans: BorderWaveFormGS,
|
pub gs_trans: BorderWaveFormGs,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BorderWaveForm {
|
impl BorderWaveForm {
|
||||||
|
|
@ -194,25 +190,24 @@ impl BorderWaveForm {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[allow(non_camel_case_types)]
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
pub enum DeepSleepMode {
|
pub enum DeepSleepMode {
|
||||||
// Sleeps and keeps access to RAM and controller
|
// Sleeps and keeps access to RAM and controller
|
||||||
NORMAL = 0x00,
|
Normal = 0x00,
|
||||||
|
|
||||||
// Sleeps without access to RAM/controller but keeps RAM content
|
// Sleeps without access to RAM/controller but keeps RAM content
|
||||||
MODE_1 = 0x01,
|
Mode1 = 0x01,
|
||||||
|
|
||||||
// Same as MODE_1 but RAM content is not kept
|
// Same as MODE_1 but RAM content is not kept
|
||||||
MODE_2 = 0x11,
|
Mode2 = 0x11,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct GateDrivingVoltage(pub u8);
|
pub(crate) struct GateDrivingVoltage(pub u8);
|
||||||
pub(crate) struct SourceDrivingVoltage(pub u8);
|
pub(crate) struct SourceDrivingVoltage(pub u8);
|
||||||
pub(crate) struct VCOM(pub u8);
|
pub(crate) struct Vcom(pub u8);
|
||||||
|
|
||||||
pub(crate) trait I32Ext {
|
pub(crate) trait I32Ext {
|
||||||
fn vcom(self) -> VCOM;
|
fn vcom(self) -> Vcom;
|
||||||
fn gate_driving_decivolt(self) -> GateDrivingVoltage;
|
fn gate_driving_decivolt(self) -> GateDrivingVoltage;
|
||||||
fn source_driving_decivolt(self) -> SourceDrivingVoltage;
|
fn source_driving_decivolt(self) -> SourceDrivingVoltage;
|
||||||
}
|
}
|
||||||
|
|
@ -220,7 +215,7 @@ pub(crate) trait I32Ext {
|
||||||
impl I32Ext for i32 {
|
impl I32Ext for i32 {
|
||||||
// This is really not very nice. Until I find something better, this will be
|
// This is really not very nice. Until I find something better, this will be
|
||||||
// a placeholder.
|
// a placeholder.
|
||||||
fn vcom(self) -> VCOM {
|
fn vcom(self) -> Vcom {
|
||||||
assert!((-30..=-2).contains(&self));
|
assert!((-30..=-2).contains(&self));
|
||||||
let u = match -self {
|
let u = match -self {
|
||||||
2 => 0x08,
|
2 => 0x08,
|
||||||
|
|
@ -254,7 +249,7 @@ impl I32Ext for i32 {
|
||||||
30 => 0x78,
|
30 => 0x78,
|
||||||
_ => 0,
|
_ => 0,
|
||||||
};
|
};
|
||||||
VCOM(u)
|
Vcom(u)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn gate_driving_decivolt(self) -> GateDrivingVoltage {
|
fn gate_driving_decivolt(self) -> GateDrivingVoltage {
|
||||||
|
|
|
||||||
|
|
@ -16,13 +16,13 @@ use embedded_hal::{
|
||||||
use crate::buffer_len;
|
use crate::buffer_len;
|
||||||
use crate::color::Color;
|
use crate::color::Color;
|
||||||
use crate::interface::DisplayInterface;
|
use crate::interface::DisplayInterface;
|
||||||
use crate::traits::{InternalWiAdditions, RefreshLUT, WaveshareDisplay};
|
use crate::traits::{InternalWiAdditions, RefreshLut, WaveshareDisplay};
|
||||||
|
|
||||||
pub(crate) mod command;
|
pub(crate) mod command;
|
||||||
use self::command::{
|
use self::command::{
|
||||||
BorderWaveForm, BorderWaveFormFixLevel, BorderWaveFormGS, BorderWaveFormVBD, Command,
|
BorderWaveForm, BorderWaveFormFixLevel, BorderWaveFormGs, BorderWaveFormVbd, Command,
|
||||||
DataEntryModeDir, DataEntryModeIncr, DeepSleepMode, DisplayUpdateControl2, DriverOutput,
|
DataEntryModeDir, DataEntryModeIncr, DeepSleepMode, DisplayUpdateControl2, DriverOutput,
|
||||||
GateDrivingVoltage, I32Ext, SourceDrivingVoltage, VCOM,
|
GateDrivingVoltage, I32Ext, SourceDrivingVoltage, Vcom,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub(crate) mod constants;
|
pub(crate) mod constants;
|
||||||
|
|
@ -43,9 +43,9 @@ pub const HEIGHT: u32 = 250;
|
||||||
pub const DEFAULT_BACKGROUND_COLOR: Color = Color::White;
|
pub const DEFAULT_BACKGROUND_COLOR: Color = Color::White;
|
||||||
const IS_BUSY_LOW: bool = false;
|
const IS_BUSY_LOW: bool = false;
|
||||||
|
|
||||||
/// EPD2in13 (V2) driver
|
/// Epd2in13 (V2) driver
|
||||||
///
|
///
|
||||||
pub struct EPD2in13<SPI, CS, BUSY, DC, RST> {
|
pub struct Epd2in13<SPI, CS, BUSY, DC, RST> {
|
||||||
/// Connection Interface
|
/// Connection Interface
|
||||||
interface: DisplayInterface<SPI, CS, BUSY, DC, RST>,
|
interface: DisplayInterface<SPI, CS, BUSY, DC, RST>,
|
||||||
|
|
||||||
|
|
@ -53,11 +53,11 @@ pub struct EPD2in13<SPI, CS, BUSY, DC, RST> {
|
||||||
|
|
||||||
/// Background Color
|
/// Background Color
|
||||||
background_color: Color,
|
background_color: Color,
|
||||||
refresh: RefreshLUT,
|
refresh: RefreshLut,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<SPI, CS, BUSY, DC, RST> InternalWiAdditions<SPI, CS, BUSY, DC, RST>
|
impl<SPI, CS, BUSY, DC, RST> InternalWiAdditions<SPI, CS, BUSY, DC, RST>
|
||||||
for EPD2in13<SPI, CS, BUSY, DC, RST>
|
for Epd2in13<SPI, CS, BUSY, DC, RST>
|
||||||
where
|
where
|
||||||
SPI: Write<u8>,
|
SPI: Write<u8>,
|
||||||
CS: OutputPin,
|
CS: OutputPin,
|
||||||
|
|
@ -73,14 +73,14 @@ where
|
||||||
// HW reset
|
// HW reset
|
||||||
self.interface.reset(delay, 10);
|
self.interface.reset(delay, 10);
|
||||||
|
|
||||||
if self.refresh == RefreshLUT::QUICK {
|
if self.refresh == RefreshLut::Quick {
|
||||||
self.set_vcom_register(spi, (-9).vcom())?;
|
self.set_vcom_register(spi, (-9).vcom())?;
|
||||||
self.wait_until_idle();
|
self.wait_until_idle();
|
||||||
|
|
||||||
self.set_lut(spi, Some(self.refresh))?;
|
self.set_lut(spi, Some(self.refresh))?;
|
||||||
|
|
||||||
// Python code does this, not sure why
|
// Python code does this, not sure why
|
||||||
// self.cmd_with_data(spi, Command::WRITE_OTP_SELECTION, &[0, 0, 0, 0, 0x40, 0, 0])?;
|
// self.cmd_with_data(spi, Command::WriteOtpSelection, &[0, 0, 0, 0, 0x40, 0, 0])?;
|
||||||
|
|
||||||
// During partial update, clock/analog are not disabled between 2
|
// During partial update, clock/analog are not disabled between 2
|
||||||
// updates.
|
// updates.
|
||||||
|
|
@ -88,20 +88,20 @@ where
|
||||||
spi,
|
spi,
|
||||||
DisplayUpdateControl2::new().enable_analog().enable_clock(),
|
DisplayUpdateControl2::new().enable_analog().enable_clock(),
|
||||||
)?;
|
)?;
|
||||||
self.command(spi, Command::MASTER_ACTIVATION)?;
|
self.command(spi, Command::MasterActivation)?;
|
||||||
self.wait_until_idle();
|
self.wait_until_idle();
|
||||||
|
|
||||||
self.set_border_waveform(
|
self.set_border_waveform(
|
||||||
spi,
|
spi,
|
||||||
BorderWaveForm {
|
BorderWaveForm {
|
||||||
vbd: BorderWaveFormVBD::GS,
|
vbd: BorderWaveFormVbd::Gs,
|
||||||
fix_level: BorderWaveFormFixLevel::VSS,
|
fix_level: BorderWaveFormFixLevel::Vss,
|
||||||
gs_trans: BorderWaveFormGS::LUT1,
|
gs_trans: BorderWaveFormGs::Lut1,
|
||||||
},
|
},
|
||||||
)?;
|
)?;
|
||||||
} else {
|
} else {
|
||||||
self.wait_until_idle();
|
self.wait_until_idle();
|
||||||
self.command(spi, Command::SW_RESET)?;
|
self.command(spi, Command::SwReset)?;
|
||||||
self.wait_until_idle();
|
self.wait_until_idle();
|
||||||
|
|
||||||
self.set_driver_output(
|
self.set_driver_output(
|
||||||
|
|
@ -118,11 +118,7 @@ where
|
||||||
self.set_dummy_line_period(spi, 0x30)?;
|
self.set_dummy_line_period(spi, 0x30)?;
|
||||||
self.set_gate_scan_start_position(spi, 0)?;
|
self.set_gate_scan_start_position(spi, 0)?;
|
||||||
|
|
||||||
self.set_data_entry_mode(
|
self.set_data_entry_mode(spi, DataEntryModeIncr::XIncrYIncr, DataEntryModeDir::XDir)?;
|
||||||
spi,
|
|
||||||
DataEntryModeIncr::X_INCR_Y_INCR,
|
|
||||||
DataEntryModeDir::X_DIR,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
// Use simple X/Y auto increase
|
// Use simple X/Y auto increase
|
||||||
self.set_ram_area(spi, 0, 0, WIDTH - 1, HEIGHT - 1)?;
|
self.set_ram_area(spi, 0, 0, WIDTH - 1, HEIGHT - 1)?;
|
||||||
|
|
@ -131,9 +127,9 @@ where
|
||||||
self.set_border_waveform(
|
self.set_border_waveform(
|
||||||
spi,
|
spi,
|
||||||
BorderWaveForm {
|
BorderWaveForm {
|
||||||
vbd: BorderWaveFormVBD::GS,
|
vbd: BorderWaveFormVbd::Gs,
|
||||||
fix_level: BorderWaveFormFixLevel::VSS,
|
fix_level: BorderWaveFormFixLevel::Vss,
|
||||||
gs_trans: BorderWaveFormGS::LUT3,
|
gs_trans: BorderWaveFormGs::Lut3,
|
||||||
},
|
},
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
|
@ -158,7 +154,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<SPI, CS, BUSY, DC, RST> WaveshareDisplay<SPI, CS, BUSY, DC, RST>
|
impl<SPI, CS, BUSY, DC, RST> WaveshareDisplay<SPI, CS, BUSY, DC, RST>
|
||||||
for EPD2in13<SPI, CS, BUSY, DC, RST>
|
for Epd2in13<SPI, CS, BUSY, DC, RST>
|
||||||
where
|
where
|
||||||
SPI: Write<u8>,
|
SPI: Write<u8>,
|
||||||
CS: OutputPin,
|
CS: OutputPin,
|
||||||
|
|
@ -175,11 +171,11 @@ where
|
||||||
rst: RST,
|
rst: RST,
|
||||||
delay: &mut DELAY,
|
delay: &mut DELAY,
|
||||||
) -> Result<Self, SPI::Error> {
|
) -> Result<Self, SPI::Error> {
|
||||||
let mut epd = EPD2in13 {
|
let mut epd = Epd2in13 {
|
||||||
interface: DisplayInterface::new(cs, busy, dc, rst),
|
interface: DisplayInterface::new(cs, busy, dc, rst),
|
||||||
sleep_mode: DeepSleepMode::MODE_1,
|
sleep_mode: DeepSleepMode::Mode1,
|
||||||
background_color: DEFAULT_BACKGROUND_COLOR,
|
background_color: DEFAULT_BACKGROUND_COLOR,
|
||||||
refresh: RefreshLUT::FULL,
|
refresh: RefreshLut::Full,
|
||||||
};
|
};
|
||||||
|
|
||||||
epd.init(spi, delay)?;
|
epd.init(spi, delay)?;
|
||||||
|
|
@ -206,7 +202,7 @@ where
|
||||||
.disable_analog()
|
.disable_analog()
|
||||||
.disable_clock(),
|
.disable_clock(),
|
||||||
)?;
|
)?;
|
||||||
self.command(spi, Command::MASTER_ACTIVATION)?;
|
self.command(spi, Command::MasterActivation)?;
|
||||||
|
|
||||||
self.set_sleep_mode(spi, self.sleep_mode)?;
|
self.set_sleep_mode(spi, self.sleep_mode)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
@ -217,14 +213,14 @@ where
|
||||||
self.set_ram_area(spi, 0, 0, WIDTH - 1, HEIGHT - 1)?;
|
self.set_ram_area(spi, 0, 0, WIDTH - 1, HEIGHT - 1)?;
|
||||||
self.set_ram_address_counters(spi, 0, 0)?;
|
self.set_ram_address_counters(spi, 0, 0)?;
|
||||||
|
|
||||||
self.cmd_with_data(spi, Command::WRITE_RAM, buffer)?;
|
self.cmd_with_data(spi, Command::WriteRam, buffer)?;
|
||||||
|
|
||||||
if self.refresh == RefreshLUT::FULL {
|
if self.refresh == RefreshLut::Full {
|
||||||
// Always keep the base buffer equal to current if not doing partial refresh.
|
// Always keep the base buffer equal to current if not doing partial refresh.
|
||||||
self.set_ram_area(spi, 0, 0, WIDTH - 1, HEIGHT - 1)?;
|
self.set_ram_area(spi, 0, 0, WIDTH - 1, HEIGHT - 1)?;
|
||||||
self.set_ram_address_counters(spi, 0, 0)?;
|
self.set_ram_address_counters(spi, 0, 0)?;
|
||||||
|
|
||||||
self.cmd_with_data(spi, Command::WRITE_RAM_RED, buffer)?;
|
self.cmd_with_data(spi, Command::WriteRamRed, buffer)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
@ -249,19 +245,19 @@ where
|
||||||
// RAM content). Using this function will most probably make the actual
|
// RAM content). Using this function will most probably make the actual
|
||||||
// display incorrect as the controler will compare with something
|
// display incorrect as the controler will compare with something
|
||||||
// incorrect.
|
// incorrect.
|
||||||
assert!(self.refresh == RefreshLUT::FULL);
|
assert!(self.refresh == RefreshLut::Full);
|
||||||
|
|
||||||
self.set_ram_area(spi, x, y, x + width, y + height)?;
|
self.set_ram_area(spi, x, y, x + width, y + height)?;
|
||||||
self.set_ram_address_counters(spi, x, y)?;
|
self.set_ram_address_counters(spi, x, y)?;
|
||||||
|
|
||||||
self.cmd_with_data(spi, Command::WRITE_RAM, buffer)?;
|
self.cmd_with_data(spi, Command::WriteRam, buffer)?;
|
||||||
|
|
||||||
if self.refresh == RefreshLUT::FULL {
|
if self.refresh == RefreshLut::Full {
|
||||||
// Always keep the base buffer equals to current if not doing partial refresh.
|
// Always keep the base buffer equals to current if not doing partial refresh.
|
||||||
self.set_ram_area(spi, x, y, x + width, y + height)?;
|
self.set_ram_area(spi, x, y, x + width, y + height)?;
|
||||||
self.set_ram_address_counters(spi, x, y)?;
|
self.set_ram_address_counters(spi, x, y)?;
|
||||||
|
|
||||||
self.cmd_with_data(spi, Command::WRITE_RAM_RED, buffer)?;
|
self.cmd_with_data(spi, Command::WriteRamRed, buffer)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
@ -270,7 +266,7 @@ where
|
||||||
/// Never use directly this function when using partial refresh, or also
|
/// Never use directly this function when using partial refresh, or also
|
||||||
/// keep the base buffer in syncd using `set_partial_base_buffer` function.
|
/// keep the base buffer in syncd using `set_partial_base_buffer` function.
|
||||||
fn display_frame(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> {
|
fn display_frame(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> {
|
||||||
if self.refresh == RefreshLUT::FULL {
|
if self.refresh == RefreshLut::Full {
|
||||||
self.set_display_update_control_2(
|
self.set_display_update_control_2(
|
||||||
spi,
|
spi,
|
||||||
DisplayUpdateControl2::new()
|
DisplayUpdateControl2::new()
|
||||||
|
|
@ -283,7 +279,7 @@ where
|
||||||
} else {
|
} else {
|
||||||
self.set_display_update_control_2(spi, DisplayUpdateControl2::new().display())?;
|
self.set_display_update_control_2(spi, DisplayUpdateControl2::new().display())?;
|
||||||
}
|
}
|
||||||
self.command(spi, Command::MASTER_ACTIVATION)?;
|
self.command(spi, Command::MasterActivation)?;
|
||||||
self.wait_until_idle();
|
self.wait_until_idle();
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
@ -293,7 +289,7 @@ where
|
||||||
self.update_frame(spi, buffer)?;
|
self.update_frame(spi, buffer)?;
|
||||||
self.display_frame(spi)?;
|
self.display_frame(spi)?;
|
||||||
|
|
||||||
if self.refresh == RefreshLUT::QUICK {
|
if self.refresh == RefreshLut::Quick {
|
||||||
self.set_partial_base_buffer(spi, buffer)?;
|
self.set_partial_base_buffer(spi, buffer)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
@ -305,7 +301,7 @@ where
|
||||||
self.set_ram_area(spi, 0, 0, WIDTH - 1, HEIGHT - 1)?;
|
self.set_ram_area(spi, 0, 0, WIDTH - 1, HEIGHT - 1)?;
|
||||||
self.set_ram_address_counters(spi, 0, 0)?;
|
self.set_ram_address_counters(spi, 0, 0)?;
|
||||||
|
|
||||||
self.command(spi, Command::WRITE_RAM)?;
|
self.command(spi, Command::WriteRam)?;
|
||||||
self.interface.data_x_times(
|
self.interface.data_x_times(
|
||||||
spi,
|
spi,
|
||||||
color,
|
color,
|
||||||
|
|
@ -313,11 +309,11 @@ where
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
// Always keep the base buffer equals to current if not doing partial refresh.
|
// Always keep the base buffer equals to current if not doing partial refresh.
|
||||||
if self.refresh == RefreshLUT::FULL {
|
if self.refresh == RefreshLut::Full {
|
||||||
self.set_ram_area(spi, 0, 0, WIDTH - 1, HEIGHT - 1)?;
|
self.set_ram_area(spi, 0, 0, WIDTH - 1, HEIGHT - 1)?;
|
||||||
self.set_ram_address_counters(spi, 0, 0)?;
|
self.set_ram_address_counters(spi, 0, 0)?;
|
||||||
|
|
||||||
self.command(spi, Command::WRITE_RAM_RED)?;
|
self.command(spi, Command::WriteRamRed)?;
|
||||||
self.interface.data_x_times(
|
self.interface.data_x_times(
|
||||||
spi,
|
spi,
|
||||||
color,
|
color,
|
||||||
|
|
@ -346,14 +342,14 @@ where
|
||||||
fn set_lut(
|
fn set_lut(
|
||||||
&mut self,
|
&mut self,
|
||||||
spi: &mut SPI,
|
spi: &mut SPI,
|
||||||
refresh_rate: Option<RefreshLUT>,
|
refresh_rate: Option<RefreshLut>,
|
||||||
) -> Result<(), SPI::Error> {
|
) -> Result<(), SPI::Error> {
|
||||||
let buffer = match refresh_rate {
|
let buffer = match refresh_rate {
|
||||||
Some(RefreshLUT::FULL) | None => &LUT_FULL_UPDATE,
|
Some(RefreshLut::Full) | None => &LUT_FULL_UPDATE,
|
||||||
Some(RefreshLUT::QUICK) => &LUT_PARTIAL_UPDATE,
|
Some(RefreshLut::Quick) => &LUT_PARTIAL_UPDATE,
|
||||||
};
|
};
|
||||||
|
|
||||||
self.cmd_with_data(spi, Command::WRITE_LUT_REGISTER, buffer)
|
self.cmd_with_data(spi, Command::WriteLutRegister, buffer)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_busy(&self) -> bool {
|
fn is_busy(&self) -> bool {
|
||||||
|
|
@ -361,7 +357,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<SPI, CS, BUSY, DC, RST> EPD2in13<SPI, CS, BUSY, DC, RST>
|
impl<SPI, CS, BUSY, DC, RST> Epd2in13<SPI, CS, BUSY, DC, RST>
|
||||||
where
|
where
|
||||||
SPI: Write<u8>,
|
SPI: Write<u8>,
|
||||||
CS: OutputPin,
|
CS: OutputPin,
|
||||||
|
|
@ -380,7 +376,7 @@ where
|
||||||
self.set_ram_area(spi, 0, 0, WIDTH - 1, HEIGHT - 1)?;
|
self.set_ram_area(spi, 0, 0, WIDTH - 1, HEIGHT - 1)?;
|
||||||
self.set_ram_address_counters(spi, 0, 0)?;
|
self.set_ram_address_counters(spi, 0, 0)?;
|
||||||
|
|
||||||
self.cmd_with_data(spi, Command::WRITE_RAM_RED, buffer)?;
|
self.cmd_with_data(spi, Command::WriteRamRed, buffer)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -395,7 +391,7 @@ where
|
||||||
&mut self,
|
&mut self,
|
||||||
spi: &mut SPI,
|
spi: &mut SPI,
|
||||||
delay: &mut DELAY,
|
delay: &mut DELAY,
|
||||||
refresh: RefreshLUT,
|
refresh: RefreshLut,
|
||||||
) -> Result<(), SPI::Error> {
|
) -> Result<(), SPI::Error> {
|
||||||
if self.refresh != refresh {
|
if self.refresh != refresh {
|
||||||
self.refresh = refresh;
|
self.refresh = refresh;
|
||||||
|
|
@ -412,7 +408,7 @@ where
|
||||||
assert!(start <= 295);
|
assert!(start <= 295);
|
||||||
self.cmd_with_data(
|
self.cmd_with_data(
|
||||||
spi,
|
spi,
|
||||||
Command::GATE_SCAN_START_POSITION,
|
Command::GateScanStartPosition,
|
||||||
&[(start & 0xFF) as u8, ((start >> 8) & 0x1) as u8],
|
&[(start & 0xFF) as u8, ((start >> 8) & 0x1) as u8],
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -424,13 +420,13 @@ where
|
||||||
) -> Result<(), SPI::Error> {
|
) -> Result<(), SPI::Error> {
|
||||||
self.cmd_with_data(
|
self.cmd_with_data(
|
||||||
spi,
|
spi,
|
||||||
Command::BORDER_WAVEFORM_CONTROL,
|
Command::BorderWaveformControl,
|
||||||
&[borderwaveform.to_u8()],
|
&[borderwaveform.to_u8()],
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_vcom_register(&mut self, spi: &mut SPI, vcom: VCOM) -> Result<(), SPI::Error> {
|
fn set_vcom_register(&mut self, spi: &mut SPI, vcom: Vcom) -> Result<(), SPI::Error> {
|
||||||
self.cmd_with_data(spi, Command::WRITE_VCOM_REGISTER, &[vcom.0])
|
self.cmd_with_data(spi, Command::WriteVcomRegister, &[vcom.0])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_gate_driving_voltage(
|
fn set_gate_driving_voltage(
|
||||||
|
|
@ -438,7 +434,7 @@ where
|
||||||
spi: &mut SPI,
|
spi: &mut SPI,
|
||||||
voltage: GateDrivingVoltage,
|
voltage: GateDrivingVoltage,
|
||||||
) -> Result<(), SPI::Error> {
|
) -> Result<(), SPI::Error> {
|
||||||
self.cmd_with_data(spi, Command::GATE_DRIVING_VOLTAGE_CTRL, &[voltage.0])
|
self.cmd_with_data(spi, Command::GateDrivingVoltageCtrl, &[voltage.0])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_dummy_line_period(
|
fn set_dummy_line_period(
|
||||||
|
|
@ -447,11 +443,11 @@ where
|
||||||
number_of_lines: u8,
|
number_of_lines: u8,
|
||||||
) -> Result<(), SPI::Error> {
|
) -> Result<(), SPI::Error> {
|
||||||
assert!(number_of_lines <= 127);
|
assert!(number_of_lines <= 127);
|
||||||
self.cmd_with_data(spi, Command::SET_DUMMY_LINE_PERIOD, &[number_of_lines])
|
self.cmd_with_data(spi, Command::SetDummyLinePeriod, &[number_of_lines])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_gate_line_width(&mut self, spi: &mut SPI, width: u8) -> Result<(), SPI::Error> {
|
fn set_gate_line_width(&mut self, spi: &mut SPI, width: u8) -> Result<(), SPI::Error> {
|
||||||
self.cmd_with_data(spi, Command::SET_GATE_LINE_WIDTH, &[width & 0x0F])
|
self.cmd_with_data(spi, Command::SetGateLineWidth, &[width & 0x0F])
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the source driving voltage value
|
/// Sets the source driving voltage value
|
||||||
|
|
@ -464,7 +460,7 @@ where
|
||||||
) -> Result<(), SPI::Error> {
|
) -> Result<(), SPI::Error> {
|
||||||
self.cmd_with_data(
|
self.cmd_with_data(
|
||||||
spi,
|
spi,
|
||||||
Command::SOURCE_DRIVING_VOLTAGE_CTRL,
|
Command::SourceDrivingVoltageCtrl,
|
||||||
&[vsh1.0, vsh2.0, vsl.0],
|
&[vsh1.0, vsh2.0, vsl.0],
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -476,16 +472,16 @@ where
|
||||||
spi: &mut SPI,
|
spi: &mut SPI,
|
||||||
value: DisplayUpdateControl2,
|
value: DisplayUpdateControl2,
|
||||||
) -> Result<(), SPI::Error> {
|
) -> Result<(), SPI::Error> {
|
||||||
self.cmd_with_data(spi, Command::DISPLAY_UPDATE_CONTROL_2, &[value.0])
|
self.cmd_with_data(spi, Command::DisplayUpdateControl2, &[value.0])
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Triggers the deep sleep mode
|
/// Triggers the deep sleep mode
|
||||||
fn set_sleep_mode(&mut self, spi: &mut SPI, mode: DeepSleepMode) -> Result<(), SPI::Error> {
|
fn set_sleep_mode(&mut self, spi: &mut SPI, mode: DeepSleepMode) -> Result<(), SPI::Error> {
|
||||||
self.cmd_with_data(spi, Command::DEEP_SLEEP_MODE, &[mode as u8])
|
self.cmd_with_data(spi, Command::DeepSleepMode, &[mode as u8])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_driver_output(&mut self, spi: &mut SPI, output: DriverOutput) -> Result<(), SPI::Error> {
|
fn set_driver_output(&mut self, spi: &mut SPI, output: DriverOutput) -> Result<(), SPI::Error> {
|
||||||
self.cmd_with_data(spi, Command::DRIVER_OUTPUT_CONTROL, &output.to_bytes())
|
self.cmd_with_data(spi, Command::DriverOutputControl, &output.to_bytes())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the data entry mode (ie. how X and Y positions changes when writing
|
/// Sets the data entry mode (ie. how X and Y positions changes when writing
|
||||||
|
|
@ -497,7 +493,7 @@ where
|
||||||
counter_direction: DataEntryModeDir,
|
counter_direction: DataEntryModeDir,
|
||||||
) -> Result<(), SPI::Error> {
|
) -> Result<(), SPI::Error> {
|
||||||
let mode = counter_incr_mode as u8 | counter_direction as u8;
|
let mode = counter_incr_mode as u8 | counter_direction as u8;
|
||||||
self.cmd_with_data(spi, Command::DATA_ENTRY_MODE_SETTING, &[mode])
|
self.cmd_with_data(spi, Command::DataEntryModeSetting, &[mode])
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets both X and Y pixels ranges
|
/// Sets both X and Y pixels ranges
|
||||||
|
|
@ -511,13 +507,13 @@ where
|
||||||
) -> Result<(), SPI::Error> {
|
) -> Result<(), SPI::Error> {
|
||||||
self.cmd_with_data(
|
self.cmd_with_data(
|
||||||
spi,
|
spi,
|
||||||
Command::SET_RAM_X_ADDRESS_START_END_POSITION,
|
Command::SetRamXAddressStartEndPosition,
|
||||||
&[(start_x >> 3) as u8, (end_x >> 3) as u8],
|
&[(start_x >> 3) as u8, (end_x >> 3) as u8],
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
self.cmd_with_data(
|
self.cmd_with_data(
|
||||||
spi,
|
spi,
|
||||||
Command::SET_RAM_Y_ADDRESS_START_END_POSITION,
|
Command::SetRamYAddressStartEndPosition,
|
||||||
&[
|
&[
|
||||||
start_y as u8,
|
start_y as u8,
|
||||||
(start_y >> 8) as u8,
|
(start_y >> 8) as u8,
|
||||||
|
|
@ -535,11 +531,11 @@ where
|
||||||
y: u32,
|
y: u32,
|
||||||
) -> Result<(), SPI::Error> {
|
) -> Result<(), SPI::Error> {
|
||||||
self.wait_until_idle();
|
self.wait_until_idle();
|
||||||
self.cmd_with_data(spi, Command::SET_RAM_X_ADDRESS_COUNTER, &[(x >> 3) as u8])?;
|
self.cmd_with_data(spi, Command::SetRamXAddressCounter, &[(x >> 3) as u8])?;
|
||||||
|
|
||||||
self.cmd_with_data(
|
self.cmd_with_data(
|
||||||
spi,
|
spi,
|
||||||
Command::SET_RAM_Y_ADDRESS_COUNTER,
|
Command::SetRamYAddressCounter,
|
||||||
&[y as u8, (y >> 8) as u8],
|
&[y as u8, (y >> 8) as u8],
|
||||||
)?;
|
)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
||||||
|
|
@ -5,117 +5,116 @@ use crate::traits;
|
||||||
///
|
///
|
||||||
/// More information can be found in the [specification](https://www.waveshare.com/w/upload/d/d8/2.7inch-e-paper-b-specification.pdf)
|
/// More information can be found in the [specification](https://www.waveshare.com/w/upload/d/d8/2.7inch-e-paper-b-specification.pdf)
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[allow(non_camel_case_types)]
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
pub(crate) enum Command {
|
pub(crate) enum Command {
|
||||||
/// Set Resolution, LUT selection, BWR pixels, gate scan direction, source shift direction, booster switch, soft reset
|
/// Set Resolution, LUT selection, BWR pixels, gate scan direction, source shift direction, booster switch, soft reset
|
||||||
PANEL_SETTING = 0x00,
|
PanelSetting = 0x00,
|
||||||
/// Selecting internal and external power
|
/// Selecting internal and external power
|
||||||
POWER_SETTING = 0x01,
|
PowerSetting = 0x01,
|
||||||
POWER_OFF = 0x02,
|
PowerOff = 0x02,
|
||||||
/// Setting Power OFF sequence
|
/// Setting Power OFF sequence
|
||||||
POWER_OFF_SEQUENCE_SETTING = 0x03,
|
PowerOffSequenceSetting = 0x03,
|
||||||
POWER_ON = 0x04,
|
PowerOn = 0x04,
|
||||||
/// This command enables the internal bandgap, which will be cleared by the next POF.
|
/// This command enables the internal bandgap, which will be cleared by the next POF.
|
||||||
POWER_ON_MEASURE = 0x05,
|
PowerOnMeasure = 0x05,
|
||||||
/// Starting data transmission
|
/// Starting data transmission
|
||||||
///
|
///
|
||||||
/// ```ignore
|
/// ```ignore
|
||||||
/// self.send_data(&[0x07, 0x07, 0x17])?;
|
/// self.send_data(&[0x07, 0x07, 0x17])?;
|
||||||
/// ```
|
/// ```
|
||||||
BOOSTER_SOFT_START = 0x06,
|
BoosterSoftStart = 0x06,
|
||||||
/// After this command is transmitted, the chip would enter the deep-sleep mode to save power.
|
/// After this command is transmitted, the chip would enter the deep-sleep mode to save power.
|
||||||
///
|
///
|
||||||
/// The deep sleep mode would return to standby by hardware reset.
|
/// The deep sleep mode would return to standby by hardware reset.
|
||||||
///
|
///
|
||||||
/// The only one parameter is a check code, the command would be excuted if check code = 0xA5.
|
/// The only one parameter is a check code, the command would be excuted if check code = 0xA5.
|
||||||
DEEP_SLEEP = 0x07,
|
DeepSleep = 0x07,
|
||||||
/// This command starts transmitting data and write them into SRAM. To complete data transmission, command DSP (Data
|
/// This command starts transmitting data and write them into SRAM. To complete data transmission, command DSP (Data
|
||||||
/// transmission Stop) must be issued. Then the chip will start to send data/VCOM for panel.
|
/// transmission Stop) must be issued. Then the chip will start to send data/VCOM for panel.
|
||||||
///
|
///
|
||||||
/// - In B/W mode, this command writes “OLD” data to SRAM.
|
/// - In B/W mode, this command writes “OLD” data to SRAM.
|
||||||
/// - In B/W/Red mode, this command writes “B/W” data to SRAM.
|
/// - In B/W/Red mode, this command writes “B/W” data to SRAM.
|
||||||
DATA_START_TRANSMISSION_1 = 0x10,
|
DataStartTransmission1 = 0x10,
|
||||||
/// Stopping data transmission
|
/// Stopping data transmission
|
||||||
DATA_STOP = 0x11,
|
DataStop = 0x11,
|
||||||
/// After this command is issued, driver will refresh display (data/VCOM) according to SRAM data and LUT.
|
/// After this command is issued, driver will refresh display (data/VCOM) according to SRAM data and LUT.
|
||||||
DISPLAY_REFRESH = 0x12,
|
DisplayRefresh = 0x12,
|
||||||
/// This command starts transmitting data and write them into SRAM. To complete data transmission, command DSP (Data
|
/// This command starts transmitting data and write them into SRAM. To complete data transmission, command DSP (Data
|
||||||
/// transmission Stop) must be issued. Then the chip will start to send data/VCOM for panel.
|
/// transmission Stop) must be issued. Then the chip will start to send data/VCOM for panel.
|
||||||
/// - In B/W mode, this command writes “NEW” data to SRAM.
|
/// - In B/W mode, this command writes “NEW” data to SRAM.
|
||||||
/// - In B/W/Red mode, this command writes “RED” data to SRAM.
|
/// - In B/W/Red mode, this command writes “RED” data to SRAM.
|
||||||
DATA_START_TRANSMISSION_2 = 0x13,
|
DataStartTransmission2 = 0x13,
|
||||||
/// The command define as follows: The register is indicates that user start to transmit data, then write to SRAM. While data transmission
|
/// The command define as follows: The register is indicates that user start to transmit data, then write to SRAM. While data transmission
|
||||||
/// complete, user must send command DSP (Data transmission Stop). Then chip will start to send data/VCOM for panel.
|
/// complete, user must send command DSP (Data transmission Stop). Then chip will start to send data/VCOM for panel.
|
||||||
///
|
///
|
||||||
/// - In B/W mode, this command writes “OLD” data to SRAM.
|
/// - In B/W mode, this command writes “OLD” data to SRAM.
|
||||||
/// - In B/W/Red mode, this command writes “B/W” data to SRAM.
|
/// - In B/W/Red mode, this command writes “B/W” data to SRAM.
|
||||||
PARTIAL_DATA_START_TRANSMISSION_1 = 0x14,
|
PartialDataStartTransmission1 = 0x14,
|
||||||
/// The command define as follows: The register is indicates that user start to transmit data, then write to SRAM. While data transmission
|
/// The command define as follows: The register is indicates that user start to transmit data, then write to SRAM. While data transmission
|
||||||
/// complete, user must send command DSP (Data transmission Stop). Then chip will start to send data/VCOM for panel.
|
/// complete, user must send command DSP (Data transmission Stop). Then chip will start to send data/VCOM for panel.
|
||||||
///
|
///
|
||||||
/// - In B/W mode, this command writes “NEW” data to SRAM.
|
/// - In B/W mode, this command writes “NEW” data to SRAM.
|
||||||
/// - In B/W/Red mode, this command writes “RED” data to SRAM.
|
/// - In B/W/Red mode, this command writes “RED” data to SRAM.
|
||||||
PARTIAL_DATA_START_TRANSMISSION_2 = 0x15,
|
PartialDataStartTransmission2 = 0x15,
|
||||||
/// While user sent this command, driver will refresh display (data/VCOM) base on SRAM data and LUT.
|
/// While user sent this command, driver will refresh display (data/VCOM) base on SRAM data and LUT.
|
||||||
///
|
///
|
||||||
/// Only the area (X,Y, W, L) would update, the others pixel output would follow VCOM LUT
|
/// Only the area (X,Y, W, L) would update, the others pixel output would follow VCOM LUT
|
||||||
PARTIAL_DISPLAY_REFRESH = 0x16,
|
PartialDisplayRefresh = 0x16,
|
||||||
/// This command builds the Look-up table for VCOM
|
/// This command builds the Look-up table for VCOM
|
||||||
LUT_FOR_VCOM = 0x20,
|
LutForVcom = 0x20,
|
||||||
LUT_WHITE_TO_WHITE = 0x21,
|
LutWhiteToWhite = 0x21,
|
||||||
LUT_BLACK_TO_WHITE = 0x22,
|
LutBlackToWhite = 0x22,
|
||||||
LUT_WHITE_TO_BLACK = 0x23,
|
LutWhiteToBlack = 0x23,
|
||||||
LUT_BLACK_TO_BLACK = 0x24,
|
LutBlackToBlack = 0x24,
|
||||||
/// The command controls the PLL clock frequency.
|
/// The command controls the PLL clock frequency.
|
||||||
PLL_CONTROL = 0x30,
|
PllControl = 0x30,
|
||||||
/// This command reads the temperature sensed by the temperature sensor.
|
/// This command reads the temperature sensed by the temperature sensor.
|
||||||
///
|
///
|
||||||
/// Doesn't work! Waveshare doesn't connect the read pin
|
/// Doesn't work! Waveshare doesn't connect the read pin
|
||||||
TEMPERATURE_SENSOR_COMMAND = 0x40,
|
TemperatureSensor = 0x40,
|
||||||
/// This command selects Internal or External temperature sensor.
|
/// This command selects Internal or External temperature sensor.
|
||||||
TEMPERATURE_SENSOR_CALIBRATION = 0x41,
|
TemperatureSensorCalibration = 0x41,
|
||||||
/// Write External Temperature Sensor
|
/// Write External Temperature Sensor
|
||||||
TEMPERATURE_SENSOR_WRITE = 0x42,
|
TemperatureSensorWrite = 0x42,
|
||||||
/// Read External Temperature Sensor
|
/// Read External Temperature Sensor
|
||||||
///
|
///
|
||||||
/// Doesn't work! Waveshare doesn't connect the read pin
|
/// Doesn't work! Waveshare doesn't connect the read pin
|
||||||
TEMPERATURE_SENSOR_READ = 0x43,
|
TemperatureSensorRead = 0x43,
|
||||||
/// This command indicates the interval of Vcom and data output. When setting the vertical back porch, the total blanking will be kept (20 Hsync)
|
/// This command indicates the interval of Vcom and data output. When setting the vertical back porch, the total blanking will be kept (20 Hsync)
|
||||||
VCOM_AND_DATA_INTERVAL_SETTING = 0x50,
|
VcomAndDataIntervalSetting = 0x50,
|
||||||
/// This command indicates the input power condition. Host can read this flag to learn the battery condition.
|
/// This command indicates the input power condition. Host can read this flag to learn the battery condition.
|
||||||
LOW_POWER_DETECTION = 0x51,
|
LowPowerDetection = 0x51,
|
||||||
/// This command defines non-overlap period of Gate and Source.
|
/// This command defines non-overlap period of Gate and Source.
|
||||||
TCON_SETTING = 0x60,
|
TconSetting = 0x60,
|
||||||
/// This command defines alternative resolution and this setting is of higher priority than the RES\[1:0\] in R00H (PSR).
|
/// This command defines alternative resolution and this setting is of higher priority than the RES\[1:0\] in R00H (PSR).
|
||||||
RESOLUTION_SETTING = 0x61,
|
ResolutionSetting = 0x61,
|
||||||
SOURCE_AND_GATE_SETTING = 0x62,
|
SourceAndGateSetting = 0x62,
|
||||||
/// This command reads the IC status.
|
/// This command reads the IC status.
|
||||||
///
|
///
|
||||||
/// Doesn't work! Waveshare doesn't connect the read pin
|
/// Doesn't work! Waveshare doesn't connect the read pin
|
||||||
GET_STATUS = 0x71,
|
GetStatus = 0x71,
|
||||||
/// Automatically measure VCOM. This command reads the IC status
|
/// Automatically measure VCOM. This command reads the IC status
|
||||||
AUTO_MEASUREMENT_VCOM = 0x80,
|
AutoMeasurementVcom = 0x80,
|
||||||
/// This command gets the VCOM value
|
/// This command gets the VCOM value
|
||||||
///
|
///
|
||||||
/// Doesn't work! Waveshare doesn't connect the read pin
|
/// Doesn't work! Waveshare doesn't connect the read pin
|
||||||
READ_VCOM_VALUE = 0x81,
|
ReadVcomValue = 0x81,
|
||||||
/// This command sets VCOM_DC value.
|
/// This command sets VCOM_DC value.
|
||||||
VCM_DC_SETTING = 0x82,
|
VcmDcSetting = 0x82,
|
||||||
/// After this command is issued, the chip would enter the program mode.
|
/// After this command is issued, the chip would enter the program mode.
|
||||||
///
|
///
|
||||||
/// After the programming procedure completed, a hardware reset is necessary for leaving program mode.
|
/// After the programming procedure completed, a hardware reset is necessary for leaving program mode.
|
||||||
///
|
///
|
||||||
/// The only one parameter is a check code, the command would be excuted if check code = 0xA5.
|
/// The only one parameter is a check code, the command would be excuted if check code = 0xA5.
|
||||||
PROGRAM_MODE = 0xA0,
|
ProgramMode = 0xA0,
|
||||||
/// After this command is issued, the chip would enter the program mode.
|
/// After this command is issued, the chip would enter the program mode.
|
||||||
ACTIVE_PROGRAMMING = 0xA1,
|
ActiveProgramming = 0xA1,
|
||||||
/// The command is used for reading the content of OTP for checking the data of programming.
|
/// The command is used for reading the content of OTP for checking the data of programming.
|
||||||
///
|
///
|
||||||
/// The value of (n) is depending on the amount of programmed data, tha max address = 0xFFF.
|
/// The value of (n) is depending on the amount of programmed data, tha max address = 0xFFF.
|
||||||
READ_OTP = 0xA2,
|
ReadOtp = 0xA2,
|
||||||
/// Not shown in commands table, but used in init sequence
|
/// Not shown in commands table, but used in init sequence
|
||||||
POWER_OPTIMIZATION = 0xf8,
|
PowerOptimization = 0xf8,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl traits::Command for Command {
|
impl traits::Command for Command {
|
||||||
|
|
@ -132,7 +131,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn command_addr() {
|
fn command_addr() {
|
||||||
assert_eq!(Command::PANEL_SETTING.address(), 0x00);
|
assert_eq!(Command::PanelSetting.address(), 0x00);
|
||||||
assert_eq!(Command::DISPLAY_REFRESH.address(), 0x12);
|
assert_eq!(Command::DisplayRefresh.address(), 0x12);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ use embedded_hal::{
|
||||||
|
|
||||||
use crate::interface::DisplayInterface;
|
use crate::interface::DisplayInterface;
|
||||||
use crate::traits::{
|
use crate::traits::{
|
||||||
InternalWiAdditions, RefreshLUT, WaveshareDisplay, WaveshareThreeColorDisplay,
|
InternalWiAdditions, RefreshLut, WaveshareDisplay, WaveshareThreeColorDisplay,
|
||||||
};
|
};
|
||||||
|
|
||||||
// The Lookup Tables for the Display
|
// The Lookup Tables for the Display
|
||||||
|
|
@ -34,8 +34,8 @@ mod graphics;
|
||||||
#[cfg(feature = "graphics")]
|
#[cfg(feature = "graphics")]
|
||||||
pub use self::graphics::Display2in7b;
|
pub use self::graphics::Display2in7b;
|
||||||
|
|
||||||
/// EPD2in7b driver
|
/// Epd2in7b driver
|
||||||
pub struct EPD2in7b<SPI, CS, BUSY, DC, RST> {
|
pub struct Epd2in7b<SPI, CS, BUSY, DC, RST> {
|
||||||
/// Connection Interface
|
/// Connection Interface
|
||||||
interface: DisplayInterface<SPI, CS, BUSY, DC, RST>,
|
interface: DisplayInterface<SPI, CS, BUSY, DC, RST>,
|
||||||
/// Background Color
|
/// Background Color
|
||||||
|
|
@ -43,7 +43,7 @@ pub struct EPD2in7b<SPI, CS, BUSY, DC, RST> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<SPI, CS, BUSY, DC, RST> InternalWiAdditions<SPI, CS, BUSY, DC, RST>
|
impl<SPI, CS, BUSY, DC, RST> InternalWiAdditions<SPI, CS, BUSY, DC, RST>
|
||||||
for EPD2in7b<SPI, CS, BUSY, DC, RST>
|
for Epd2in7b<SPI, CS, BUSY, DC, RST>
|
||||||
where
|
where
|
||||||
SPI: Write<u8>,
|
SPI: Write<u8>,
|
||||||
CS: OutputPin,
|
CS: OutputPin,
|
||||||
|
|
@ -60,51 +60,51 @@ where
|
||||||
self.interface.reset(delay, 2);
|
self.interface.reset(delay, 2);
|
||||||
|
|
||||||
// power on
|
// power on
|
||||||
self.command(spi, Command::POWER_ON)?;
|
self.command(spi, Command::PowerOn)?;
|
||||||
delay.delay_ms(5);
|
delay.delay_ms(5);
|
||||||
self.wait_until_idle();
|
self.wait_until_idle();
|
||||||
|
|
||||||
// set panel settings, 0xbf is bw, 0xaf is multi-color
|
// set panel settings, 0xbf is bw, 0xaf is multi-color
|
||||||
self.interface
|
self.interface
|
||||||
.cmd_with_data(spi, Command::PANEL_SETTING, &[0xaf])?;
|
.cmd_with_data(spi, Command::PanelSetting, &[0xaf])?;
|
||||||
|
|
||||||
// pll control
|
// pll control
|
||||||
self.interface
|
self.interface
|
||||||
.cmd_with_data(spi, Command::PLL_CONTROL, &[0x3a])?;
|
.cmd_with_data(spi, Command::PllControl, &[0x3a])?;
|
||||||
|
|
||||||
// set the power settings
|
// set the power settings
|
||||||
self.interface.cmd_with_data(
|
self.interface.cmd_with_data(
|
||||||
spi,
|
spi,
|
||||||
Command::POWER_SETTING,
|
Command::PowerSetting,
|
||||||
&[0x03, 0x00, 0x2b, 0x2b, 0x09],
|
&[0x03, 0x00, 0x2b, 0x2b, 0x09],
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
// start the booster
|
// start the booster
|
||||||
self.interface
|
self.interface
|
||||||
.cmd_with_data(spi, Command::BOOSTER_SOFT_START, &[0x07, 0x07, 0x17])?;
|
.cmd_with_data(spi, Command::BoosterSoftStart, &[0x07, 0x07, 0x17])?;
|
||||||
|
|
||||||
// power optimization
|
// power optimization
|
||||||
self.interface
|
self.interface
|
||||||
.cmd_with_data(spi, Command::POWER_OPTIMIZATION, &[0x60, 0xa5])?;
|
.cmd_with_data(spi, Command::PowerOptimization, &[0x60, 0xa5])?;
|
||||||
self.interface
|
self.interface
|
||||||
.cmd_with_data(spi, Command::POWER_OPTIMIZATION, &[0x89, 0xa5])?;
|
.cmd_with_data(spi, Command::PowerOptimization, &[0x89, 0xa5])?;
|
||||||
self.interface
|
self.interface
|
||||||
.cmd_with_data(spi, Command::POWER_OPTIMIZATION, &[0x90, 0x00])?;
|
.cmd_with_data(spi, Command::PowerOptimization, &[0x90, 0x00])?;
|
||||||
self.interface
|
self.interface
|
||||||
.cmd_with_data(spi, Command::POWER_OPTIMIZATION, &[0x93, 0x2a])?;
|
.cmd_with_data(spi, Command::PowerOptimization, &[0x93, 0x2a])?;
|
||||||
self.interface
|
self.interface
|
||||||
.cmd_with_data(spi, Command::POWER_OPTIMIZATION, &[0x73, 0x41])?;
|
.cmd_with_data(spi, Command::PowerOptimization, &[0x73, 0x41])?;
|
||||||
|
|
||||||
self.interface
|
self.interface
|
||||||
.cmd_with_data(spi, Command::VCM_DC_SETTING, &[0x12])?;
|
.cmd_with_data(spi, Command::VcmDcSetting, &[0x12])?;
|
||||||
|
|
||||||
self.interface
|
self.interface
|
||||||
.cmd_with_data(spi, Command::VCOM_AND_DATA_INTERVAL_SETTING, &[0x87])?;
|
.cmd_with_data(spi, Command::VcomAndDataIntervalSetting, &[0x87])?;
|
||||||
|
|
||||||
self.set_lut(spi, None)?;
|
self.set_lut(spi, None)?;
|
||||||
|
|
||||||
self.interface
|
self.interface
|
||||||
.cmd_with_data(spi, Command::PARTIAL_DISPLAY_REFRESH, &[0x00])?;
|
.cmd_with_data(spi, Command::PartialDisplayRefresh, &[0x00])?;
|
||||||
|
|
||||||
self.wait_until_idle();
|
self.wait_until_idle();
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
@ -112,7 +112,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<SPI, CS, BUSY, DC, RST> WaveshareDisplay<SPI, CS, BUSY, DC, RST>
|
impl<SPI, CS, BUSY, DC, RST> WaveshareDisplay<SPI, CS, BUSY, DC, RST>
|
||||||
for EPD2in7b<SPI, CS, BUSY, DC, RST>
|
for Epd2in7b<SPI, CS, BUSY, DC, RST>
|
||||||
where
|
where
|
||||||
SPI: Write<u8>,
|
SPI: Write<u8>,
|
||||||
CS: OutputPin,
|
CS: OutputPin,
|
||||||
|
|
@ -132,7 +132,7 @@ where
|
||||||
let interface = DisplayInterface::new(cs, busy, dc, rst);
|
let interface = DisplayInterface::new(cs, busy, dc, rst);
|
||||||
let color = DEFAULT_BACKGROUND_COLOR;
|
let color = DEFAULT_BACKGROUND_COLOR;
|
||||||
|
|
||||||
let mut epd = EPD2in7b { interface, color };
|
let mut epd = Epd2in7b { interface, color };
|
||||||
|
|
||||||
epd.init(spi, delay)?;
|
epd.init(spi, delay)?;
|
||||||
|
|
||||||
|
|
@ -150,27 +150,25 @@ where
|
||||||
fn sleep(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> {
|
fn sleep(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> {
|
||||||
self.wait_until_idle();
|
self.wait_until_idle();
|
||||||
self.interface
|
self.interface
|
||||||
.cmd_with_data(spi, Command::VCOM_AND_DATA_INTERVAL_SETTING, &[0xf7])?;
|
.cmd_with_data(spi, Command::VcomAndDataIntervalSetting, &[0xf7])?;
|
||||||
|
|
||||||
self.command(spi, Command::POWER_OFF)?;
|
self.command(spi, Command::PowerOff)?;
|
||||||
self.wait_until_idle();
|
self.wait_until_idle();
|
||||||
self.interface
|
self.interface
|
||||||
.cmd_with_data(spi, Command::DEEP_SLEEP, &[0xA5])?;
|
.cmd_with_data(spi, Command::DeepSleep, &[0xA5])?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_frame(&mut self, spi: &mut SPI, buffer: &[u8]) -> Result<(), SPI::Error> {
|
fn update_frame(&mut self, spi: &mut SPI, buffer: &[u8]) -> Result<(), SPI::Error> {
|
||||||
self.interface
|
self.interface.cmd(spi, Command::DataStartTransmission1)?;
|
||||||
.cmd(spi, Command::DATA_START_TRANSMISSION_1)?;
|
|
||||||
self.send_buffer_helper(spi, buffer)?;
|
self.send_buffer_helper(spi, buffer)?;
|
||||||
|
|
||||||
// Clear chromatic layer since we won't be using it here
|
// Clear chromatic layer since we won't be using it here
|
||||||
self.interface
|
self.interface.cmd(spi, Command::DataStartTransmission2)?;
|
||||||
.cmd(spi, Command::DATA_START_TRANSMISSION_2)?;
|
|
||||||
self.interface
|
self.interface
|
||||||
.data_x_times(spi, !self.color.get_byte_value(), WIDTH * HEIGHT / 8)?;
|
.data_x_times(spi, !self.color.get_byte_value(), WIDTH * HEIGHT / 8)?;
|
||||||
|
|
||||||
self.interface.cmd(spi, Command::DATA_STOP)?;
|
self.interface.cmd(spi, Command::DataStop)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -184,7 +182,7 @@ where
|
||||||
height: u32,
|
height: u32,
|
||||||
) -> Result<(), SPI::Error> {
|
) -> Result<(), SPI::Error> {
|
||||||
self.interface
|
self.interface
|
||||||
.cmd(spi, Command::PARTIAL_DATA_START_TRANSMISSION_1)?;
|
.cmd(spi, Command::PartialDataStartTransmission1)?;
|
||||||
|
|
||||||
self.send_data(spi, &[(x >> 8) as u8])?;
|
self.send_data(spi, &[(x >> 8) as u8])?;
|
||||||
self.send_data(spi, &[(x & 0xf8) as u8])?;
|
self.send_data(spi, &[(x & 0xf8) as u8])?;
|
||||||
|
|
@ -198,18 +196,18 @@ where
|
||||||
|
|
||||||
self.send_buffer_helper(spi, buffer)?;
|
self.send_buffer_helper(spi, buffer)?;
|
||||||
|
|
||||||
self.interface.cmd(spi, Command::DATA_STOP)
|
self.interface.cmd(spi, Command::DataStop)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn display_frame(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> {
|
fn display_frame(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> {
|
||||||
self.command(spi, Command::DISPLAY_REFRESH)?;
|
self.command(spi, Command::DisplayRefresh)?;
|
||||||
self.wait_until_idle();
|
self.wait_until_idle();
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_and_display_frame(&mut self, spi: &mut SPI, buffer: &[u8]) -> Result<(), SPI::Error> {
|
fn update_and_display_frame(&mut self, spi: &mut SPI, buffer: &[u8]) -> Result<(), SPI::Error> {
|
||||||
self.update_frame(spi, buffer)?;
|
self.update_frame(spi, buffer)?;
|
||||||
self.command(spi, Command::DISPLAY_REFRESH)?;
|
self.command(spi, Command::DisplayRefresh)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -217,18 +215,16 @@ where
|
||||||
self.wait_until_idle();
|
self.wait_until_idle();
|
||||||
|
|
||||||
let color_value = self.color.get_byte_value();
|
let color_value = self.color.get_byte_value();
|
||||||
self.interface
|
self.interface.cmd(spi, Command::DataStartTransmission1)?;
|
||||||
.cmd(spi, Command::DATA_START_TRANSMISSION_1)?;
|
|
||||||
self.interface
|
self.interface
|
||||||
.data_x_times(spi, color_value, WIDTH * HEIGHT / 8)?;
|
.data_x_times(spi, color_value, WIDTH * HEIGHT / 8)?;
|
||||||
|
|
||||||
self.interface.cmd(spi, Command::DATA_STOP)?;
|
self.interface.cmd(spi, Command::DataStop)?;
|
||||||
|
|
||||||
self.interface
|
self.interface.cmd(spi, Command::DataStartTransmission2)?;
|
||||||
.cmd(spi, Command::DATA_START_TRANSMISSION_2)?;
|
|
||||||
self.interface
|
self.interface
|
||||||
.data_x_times(spi, color_value, WIDTH * HEIGHT / 8)?;
|
.data_x_times(spi, color_value, WIDTH * HEIGHT / 8)?;
|
||||||
self.interface.cmd(spi, Command::DATA_STOP)?;
|
self.interface.cmd(spi, Command::DataStop)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -251,14 +247,14 @@ where
|
||||||
fn set_lut(
|
fn set_lut(
|
||||||
&mut self,
|
&mut self,
|
||||||
spi: &mut SPI,
|
spi: &mut SPI,
|
||||||
_refresh_rate: Option<RefreshLUT>,
|
_refresh_rate: Option<RefreshLut>,
|
||||||
) -> Result<(), SPI::Error> {
|
) -> Result<(), SPI::Error> {
|
||||||
self.wait_until_idle();
|
self.wait_until_idle();
|
||||||
self.cmd_with_data(spi, Command::LUT_FOR_VCOM, &LUT_VCOM_DC)?;
|
self.cmd_with_data(spi, Command::LutForVcom, &LUT_VCOM_DC)?;
|
||||||
self.cmd_with_data(spi, Command::LUT_WHITE_TO_WHITE, &LUT_WW)?;
|
self.cmd_with_data(spi, Command::LutWhiteToWhite, &LUT_WW)?;
|
||||||
self.cmd_with_data(spi, Command::LUT_BLACK_TO_WHITE, &LUT_BW)?;
|
self.cmd_with_data(spi, Command::LutBlackToWhite, &LUT_BW)?;
|
||||||
self.cmd_with_data(spi, Command::LUT_WHITE_TO_BLACK, &LUT_WB)?;
|
self.cmd_with_data(spi, Command::LutWhiteToBlack, &LUT_WB)?;
|
||||||
self.cmd_with_data(spi, Command::LUT_BLACK_TO_BLACK, &LUT_BB)?;
|
self.cmd_with_data(spi, Command::LutBlackToBlack, &LUT_BB)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -268,7 +264,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<SPI, CS, BUSY, DC, RST> WaveshareThreeColorDisplay<SPI, CS, BUSY, DC, RST>
|
impl<SPI, CS, BUSY, DC, RST> WaveshareThreeColorDisplay<SPI, CS, BUSY, DC, RST>
|
||||||
for EPD2in7b<SPI, CS, BUSY, DC, RST>
|
for Epd2in7b<SPI, CS, BUSY, DC, RST>
|
||||||
where
|
where
|
||||||
SPI: Write<u8>,
|
SPI: Write<u8>,
|
||||||
CS: OutputPin,
|
CS: OutputPin,
|
||||||
|
|
@ -294,12 +290,11 @@ where
|
||||||
spi: &mut SPI,
|
spi: &mut SPI,
|
||||||
achromatic: &[u8],
|
achromatic: &[u8],
|
||||||
) -> Result<(), SPI::Error> {
|
) -> Result<(), SPI::Error> {
|
||||||
self.interface
|
self.interface.cmd(spi, Command::DataStartTransmission1)?;
|
||||||
.cmd(spi, Command::DATA_START_TRANSMISSION_1)?;
|
|
||||||
|
|
||||||
self.send_buffer_helper(spi, achromatic)?;
|
self.send_buffer_helper(spi, achromatic)?;
|
||||||
|
|
||||||
self.interface.cmd(spi, Command::DATA_STOP)
|
self.interface.cmd(spi, Command::DataStop)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Update only chromatic data of the display.
|
/// Update only chromatic data of the display.
|
||||||
|
|
@ -310,19 +305,18 @@ where
|
||||||
spi: &mut SPI,
|
spi: &mut SPI,
|
||||||
chromatic: &[u8],
|
chromatic: &[u8],
|
||||||
) -> Result<(), SPI::Error> {
|
) -> Result<(), SPI::Error> {
|
||||||
self.interface
|
self.interface.cmd(spi, Command::DataStartTransmission2)?;
|
||||||
.cmd(spi, Command::DATA_START_TRANSMISSION_2)?;
|
|
||||||
|
|
||||||
self.send_buffer_helper(spi, chromatic)?;
|
self.send_buffer_helper(spi, chromatic)?;
|
||||||
|
|
||||||
self.interface.cmd(spi, Command::DATA_STOP)?;
|
self.interface.cmd(spi, Command::DataStop)?;
|
||||||
self.wait_until_idle();
|
self.wait_until_idle();
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<SPI, CS, BUSY, DC, RST> EPD2in7b<SPI, CS, BUSY, DC, RST>
|
impl<SPI, CS, BUSY, DC, RST> Epd2in7b<SPI, CS, BUSY, DC, RST>
|
||||||
where
|
where
|
||||||
SPI: Write<u8>,
|
SPI: Write<u8>,
|
||||||
CS: OutputPin,
|
CS: OutputPin,
|
||||||
|
|
@ -369,7 +363,7 @@ where
|
||||||
width: u32,
|
width: u32,
|
||||||
height: u32,
|
height: u32,
|
||||||
) -> Result<(), SPI::Error> {
|
) -> Result<(), SPI::Error> {
|
||||||
self.command(spi, Command::PARTIAL_DISPLAY_REFRESH)?;
|
self.command(spi, Command::PartialDisplayRefresh)?;
|
||||||
self.send_data(spi, &[(x >> 8) as u8])?;
|
self.send_data(spi, &[(x >> 8) as u8])?;
|
||||||
self.send_data(spi, &[(x & 0xf8) as u8])?;
|
self.send_data(spi, &[(x & 0xf8) as u8])?;
|
||||||
self.send_data(spi, &[(y >> 8) as u8])?;
|
self.send_data(spi, &[(y >> 8) as u8])?;
|
||||||
|
|
@ -393,7 +387,7 @@ where
|
||||||
height: u32,
|
height: u32,
|
||||||
) -> Result<(), SPI::Error> {
|
) -> Result<(), SPI::Error> {
|
||||||
self.interface
|
self.interface
|
||||||
.cmd(spi, Command::PARTIAL_DATA_START_TRANSMISSION_1)?;
|
.cmd(spi, Command::PartialDataStartTransmission1)?;
|
||||||
self.send_data(spi, &[(x >> 8) as u8])?;
|
self.send_data(spi, &[(x >> 8) as u8])?;
|
||||||
self.send_data(spi, &[(x & 0xf8) as u8])?;
|
self.send_data(spi, &[(x & 0xf8) as u8])?;
|
||||||
self.send_data(spi, &[(y >> 8) as u8])?;
|
self.send_data(spi, &[(y >> 8) as u8])?;
|
||||||
|
|
@ -423,7 +417,7 @@ where
|
||||||
height: u32,
|
height: u32,
|
||||||
) -> Result<(), SPI::Error> {
|
) -> Result<(), SPI::Error> {
|
||||||
self.interface
|
self.interface
|
||||||
.cmd(spi, Command::PARTIAL_DATA_START_TRANSMISSION_2)?;
|
.cmd(spi, Command::PartialDataStartTransmission2)?;
|
||||||
self.send_data(spi, &[(x >> 8) as u8])?;
|
self.send_data(spi, &[(x >> 8) as u8])?;
|
||||||
self.send_data(spi, &[(x & 0xf8) as u8])?;
|
self.send_data(spi, &[(x & 0xf8) as u8])?;
|
||||||
self.send_data(spi, &[(y >> 8) as u8])?;
|
self.send_data(spi, &[(y >> 8) as u8])?;
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@
|
||||||
//!# let mut delay = delay::MockNoop::new();
|
//!# let mut delay = delay::MockNoop::new();
|
||||||
//!
|
//!
|
||||||
//!// Setup EPD
|
//!// Setup EPD
|
||||||
//!let mut epd = EPD2in9::new(&mut spi, cs_pin, busy_in, dc, rst, &mut delay)?;
|
//!let mut epd = Epd2in9::new(&mut spi, cs_pin, busy_in, dc, rst, &mut delay)?;
|
||||||
//!
|
//!
|
||||||
//!// Use display graphics from embedded-graphics
|
//!// Use display graphics from embedded-graphics
|
||||||
//!let mut display = Display2in9::default();
|
//!let mut display = Display2in9::default();
|
||||||
|
|
@ -70,18 +70,18 @@ mod graphics;
|
||||||
#[cfg(feature = "graphics")]
|
#[cfg(feature = "graphics")]
|
||||||
pub use crate::epd2in9::graphics::Display2in9;
|
pub use crate::epd2in9::graphics::Display2in9;
|
||||||
|
|
||||||
/// EPD2in9 driver
|
/// Epd2in9 driver
|
||||||
///
|
///
|
||||||
pub struct EPD2in9<SPI, CS, BUSY, DC, RST> {
|
pub struct Epd2in9<SPI, CS, BUSY, DC, RST> {
|
||||||
/// SPI
|
/// SPI
|
||||||
interface: DisplayInterface<SPI, CS, BUSY, DC, RST>,
|
interface: DisplayInterface<SPI, CS, BUSY, DC, RST>,
|
||||||
/// Color
|
/// Color
|
||||||
background_color: Color,
|
background_color: Color,
|
||||||
/// Refresh LUT
|
/// Refresh LUT
|
||||||
refresh: RefreshLUT,
|
refresh: RefreshLut,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<SPI, CS, BUSY, DC, RST> EPD2in9<SPI, CS, BUSY, DC, RST>
|
impl<SPI, CS, BUSY, DC, RST> Epd2in9<SPI, CS, BUSY, DC, RST>
|
||||||
where
|
where
|
||||||
SPI: Write<u8>,
|
SPI: Write<u8>,
|
||||||
CS: OutputPin,
|
CS: OutputPin,
|
||||||
|
|
@ -104,42 +104,39 @@ where
|
||||||
// 0.. B[2:0]
|
// 0.. B[2:0]
|
||||||
// Default Values: A = Height of Screen (0x127), B = 0x00 (GD, SM and TB=0?)
|
// Default Values: A = Height of Screen (0x127), B = 0x00 (GD, SM and TB=0?)
|
||||||
self.interface
|
self.interface
|
||||||
.cmd_with_data(spi, Command::DRIVER_OUTPUT_CONTROL, &[0x27, 0x01, 0x00])?;
|
.cmd_with_data(spi, Command::DriverOutputControl, &[0x27, 0x01, 0x00])?;
|
||||||
|
|
||||||
// 3 Databytes: (and default values from datasheet and arduino)
|
// 3 Databytes: (and default values from datasheet and arduino)
|
||||||
// 1 .. A[6:0] = 0xCF | 0xD7
|
// 1 .. A[6:0] = 0xCF | 0xD7
|
||||||
// 1 .. B[6:0] = 0xCE | 0xD6
|
// 1 .. B[6:0] = 0xCE | 0xD6
|
||||||
// 1 .. C[6:0] = 0x8D | 0x9D
|
// 1 .. C[6:0] = 0x8D | 0x9D
|
||||||
//TODO: test
|
//TODO: test
|
||||||
self.interface.cmd_with_data(
|
self.interface
|
||||||
spi,
|
.cmd_with_data(spi, Command::BoosterSoftStartControl, &[0xD7, 0xD6, 0x9D])?;
|
||||||
Command::BOOSTER_SOFT_START_CONTROL,
|
|
||||||
&[0xD7, 0xD6, 0x9D],
|
|
||||||
)?;
|
|
||||||
|
|
||||||
// One Databyte with value 0xA8 for 7V VCOM
|
// One Databyte with value 0xA8 for 7V VCOM
|
||||||
self.interface
|
self.interface
|
||||||
.cmd_with_data(spi, Command::WRITE_VCOM_REGISTER, &[0xA8])?;
|
.cmd_with_data(spi, Command::WriteVcomRegister, &[0xA8])?;
|
||||||
|
|
||||||
// One Databyte with default value 0x1A for 4 dummy lines per gate
|
// One Databyte with default value 0x1A for 4 dummy lines per gate
|
||||||
self.interface
|
self.interface
|
||||||
.cmd_with_data(spi, Command::SET_DUMMY_LINE_PERIOD, &[0x1A])?;
|
.cmd_with_data(spi, Command::SetDummyLinePeriod, &[0x1A])?;
|
||||||
|
|
||||||
// One Databyte with default value 0x08 for 2us per line
|
// One Databyte with default value 0x08 for 2us per line
|
||||||
self.interface
|
self.interface
|
||||||
.cmd_with_data(spi, Command::SET_GATE_LINE_WIDTH, &[0x08])?;
|
.cmd_with_data(spi, Command::SetGateLineWidth, &[0x08])?;
|
||||||
|
|
||||||
// One Databyte with default value 0x03
|
// One Databyte with default value 0x03
|
||||||
// -> address: x increment, y increment, address counter is updated in x direction
|
// -> address: x increment, y increment, address counter is updated in x direction
|
||||||
self.interface
|
self.interface
|
||||||
.cmd_with_data(spi, Command::DATA_ENTRY_MODE_SETTING, &[0x03])?;
|
.cmd_with_data(spi, Command::DataEntryModeSetting, &[0x03])?;
|
||||||
|
|
||||||
self.set_lut(spi, None)
|
self.set_lut(spi, None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<SPI, CS, BUSY, DC, RST> WaveshareDisplay<SPI, CS, BUSY, DC, RST>
|
impl<SPI, CS, BUSY, DC, RST> WaveshareDisplay<SPI, CS, BUSY, DC, RST>
|
||||||
for EPD2in9<SPI, CS, BUSY, DC, RST>
|
for Epd2in9<SPI, CS, BUSY, DC, RST>
|
||||||
where
|
where
|
||||||
SPI: Write<u8>,
|
SPI: Write<u8>,
|
||||||
CS: OutputPin,
|
CS: OutputPin,
|
||||||
|
|
@ -166,10 +163,10 @@ where
|
||||||
) -> Result<Self, SPI::Error> {
|
) -> Result<Self, SPI::Error> {
|
||||||
let interface = DisplayInterface::new(cs, busy, dc, rst);
|
let interface = DisplayInterface::new(cs, busy, dc, rst);
|
||||||
|
|
||||||
let mut epd = EPD2in9 {
|
let mut epd = Epd2in9 {
|
||||||
interface,
|
interface,
|
||||||
background_color: DEFAULT_BACKGROUND_COLOR,
|
background_color: DEFAULT_BACKGROUND_COLOR,
|
||||||
refresh: RefreshLUT::FULL,
|
refresh: RefreshLut::Full,
|
||||||
};
|
};
|
||||||
|
|
||||||
epd.init(spi, delay)?;
|
epd.init(spi, delay)?;
|
||||||
|
|
@ -182,7 +179,7 @@ where
|
||||||
// 0x00 for Normal mode (Power on Reset), 0x01 for Deep Sleep Mode
|
// 0x00 for Normal mode (Power on Reset), 0x01 for Deep Sleep Mode
|
||||||
//TODO: is 0x00 needed here? (see also epd1in54)
|
//TODO: is 0x00 needed here? (see also epd1in54)
|
||||||
self.interface
|
self.interface
|
||||||
.cmd_with_data(spi, Command::DEEP_SLEEP_MODE, &[0x00])?;
|
.cmd_with_data(spi, Command::DeepSleepMode, &[0x00])?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -201,7 +198,7 @@ where
|
||||||
self.use_full_frame(spi)?;
|
self.use_full_frame(spi)?;
|
||||||
|
|
||||||
self.interface
|
self.interface
|
||||||
.cmd_with_data(spi, Command::WRITE_RAM, buffer)?;
|
.cmd_with_data(spi, Command::WriteRam, buffer)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -220,7 +217,7 @@ where
|
||||||
self.set_ram_counter(spi, x, y)?;
|
self.set_ram_counter(spi, x, y)?;
|
||||||
|
|
||||||
self.interface
|
self.interface
|
||||||
.cmd_with_data(spi, Command::WRITE_RAM, buffer)?;
|
.cmd_with_data(spi, Command::WriteRam, buffer)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -229,12 +226,12 @@ where
|
||||||
// enable clock signal, enable cp, display pattern -> 0xC4 (tested with the arduino version)
|
// enable clock signal, enable cp, display pattern -> 0xC4 (tested with the arduino version)
|
||||||
//TODO: test control_1 or control_2 with default value 0xFF (from the datasheet)
|
//TODO: test control_1 or control_2 with default value 0xFF (from the datasheet)
|
||||||
self.interface
|
self.interface
|
||||||
.cmd_with_data(spi, Command::DISPLAY_UPDATE_CONTROL_2, &[0xC4])?;
|
.cmd_with_data(spi, Command::DisplayUpdateControl2, &[0xC4])?;
|
||||||
|
|
||||||
self.interface.cmd(spi, Command::MASTER_ACTIVATION)?;
|
self.interface.cmd(spi, Command::MasterActivation)?;
|
||||||
// MASTER Activation should not be interupted to avoid currption of panel images
|
// MASTER Activation should not be interupted to avoid currption of panel images
|
||||||
// therefore a terminate command is send
|
// therefore a terminate command is send
|
||||||
self.interface.cmd(spi, Command::NOP)?;
|
self.interface.cmd(spi, Command::Nop)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -251,7 +248,7 @@ where
|
||||||
// clear the ram with the background color
|
// clear the ram with the background color
|
||||||
let color = self.background_color.get_byte_value();
|
let color = self.background_color.get_byte_value();
|
||||||
|
|
||||||
self.interface.cmd(spi, Command::WRITE_RAM)?;
|
self.interface.cmd(spi, Command::WriteRam)?;
|
||||||
self.interface
|
self.interface
|
||||||
.data_x_times(spi, color, WIDTH / 8 * HEIGHT)?;
|
.data_x_times(spi, color, WIDTH / 8 * HEIGHT)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
@ -268,14 +265,14 @@ where
|
||||||
fn set_lut(
|
fn set_lut(
|
||||||
&mut self,
|
&mut self,
|
||||||
spi: &mut SPI,
|
spi: &mut SPI,
|
||||||
refresh_rate: Option<RefreshLUT>,
|
refresh_rate: Option<RefreshLut>,
|
||||||
) -> Result<(), SPI::Error> {
|
) -> Result<(), SPI::Error> {
|
||||||
if let Some(refresh_lut) = refresh_rate {
|
if let Some(refresh_lut) = refresh_rate {
|
||||||
self.refresh = refresh_lut;
|
self.refresh = refresh_lut;
|
||||||
}
|
}
|
||||||
match self.refresh {
|
match self.refresh {
|
||||||
RefreshLUT::FULL => self.set_lut_helper(spi, &LUT_FULL_UPDATE),
|
RefreshLut::Full => self.set_lut_helper(spi, &LUT_FULL_UPDATE),
|
||||||
RefreshLUT::QUICK => self.set_lut_helper(spi, &LUT_PARTIAL_UPDATE),
|
RefreshLut::Quick => self.set_lut_helper(spi, &LUT_PARTIAL_UPDATE),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -284,7 +281,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<SPI, CS, BUSY, DC, RST> EPD2in9<SPI, CS, BUSY, DC, RST>
|
impl<SPI, CS, BUSY, DC, RST> Epd2in9<SPI, CS, BUSY, DC, RST>
|
||||||
where
|
where
|
||||||
SPI: Write<u8>,
|
SPI: Write<u8>,
|
||||||
CS: OutputPin,
|
CS: OutputPin,
|
||||||
|
|
@ -319,14 +316,14 @@ where
|
||||||
// aren't relevant
|
// aren't relevant
|
||||||
self.interface.cmd_with_data(
|
self.interface.cmd_with_data(
|
||||||
spi,
|
spi,
|
||||||
Command::SET_RAM_X_ADDRESS_START_END_POSITION,
|
Command::SetRamXAddressStartEndPosition,
|
||||||
&[(start_x >> 3) as u8, (end_x >> 3) as u8],
|
&[(start_x >> 3) as u8, (end_x >> 3) as u8],
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
// 2 Databytes: A[7:0] & 0..A[8] for each - start and end
|
// 2 Databytes: A[7:0] & 0..A[8] for each - start and end
|
||||||
self.interface.cmd_with_data(
|
self.interface.cmd_with_data(
|
||||||
spi,
|
spi,
|
||||||
Command::SET_RAM_Y_ADDRESS_START_END_POSITION,
|
Command::SetRamYAddressStartEndPosition,
|
||||||
&[
|
&[
|
||||||
start_y as u8,
|
start_y as u8,
|
||||||
(start_y >> 8) as u8,
|
(start_y >> 8) as u8,
|
||||||
|
|
@ -341,12 +338,12 @@ where
|
||||||
// x is positioned in bytes, so the last 3 bits which show the position inside a byte in the ram
|
// x is positioned in bytes, so the last 3 bits which show the position inside a byte in the ram
|
||||||
// aren't relevant
|
// aren't relevant
|
||||||
self.interface
|
self.interface
|
||||||
.cmd_with_data(spi, Command::SET_RAM_X_ADDRESS_COUNTER, &[(x >> 3) as u8])?;
|
.cmd_with_data(spi, Command::SetRamXAddressCounter, &[(x >> 3) as u8])?;
|
||||||
|
|
||||||
// 2 Databytes: A[7:0] & 0..A[8]
|
// 2 Databytes: A[7:0] & 0..A[8]
|
||||||
self.interface.cmd_with_data(
|
self.interface.cmd_with_data(
|
||||||
spi,
|
spi,
|
||||||
Command::SET_RAM_Y_ADDRESS_COUNTER,
|
Command::SetRamYAddressCounter,
|
||||||
&[y as u8, (y >> 8) as u8],
|
&[y as u8, (y >> 8) as u8],
|
||||||
)?;
|
)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
@ -357,7 +354,7 @@ where
|
||||||
self.wait_until_idle();
|
self.wait_until_idle();
|
||||||
assert!(buffer.len() == 30);
|
assert!(buffer.len() == 30);
|
||||||
self.interface
|
self.interface
|
||||||
.cmd_with_data(spi, Command::WRITE_LUT_REGISTER, buffer)?;
|
.cmd_with_data(spi, Command::WriteLutRegister, buffer)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,33 +2,32 @@
|
||||||
use crate::traits;
|
use crate::traits;
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[allow(non_camel_case_types)]
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
pub(crate) enum Command {
|
pub(crate) enum Command {
|
||||||
PANEL_SETTING = 0x00,
|
PanelSetting = 0x00,
|
||||||
|
|
||||||
POWER_SETTING = 0x01,
|
PowerSetting = 0x01,
|
||||||
POWER_OFF = 0x02,
|
PowerOff = 0x02,
|
||||||
POWER_ON = 0x04,
|
PowerOn = 0x04,
|
||||||
BOOSTER_SOFT_START = 0x06,
|
BoosterSoftStart = 0x06,
|
||||||
DEEP_SLEEP = 0x07,
|
DeepSleep = 0x07,
|
||||||
DATA_START_TRANSMISSION_1 = 0x10,
|
DataStartTransmission1 = 0x10,
|
||||||
DISPLAY_REFRESH = 0x12,
|
DisplayRefresh = 0x12,
|
||||||
DATA_START_TRANSMISSION_2 = 0x13,
|
DataStartTransmission2 = 0x13,
|
||||||
|
|
||||||
LUT_FOR_VCOM = 0x20,
|
LutForVcom = 0x20,
|
||||||
LUT_WHITE_TO_WHITE = 0x21,
|
LutWhiteToWhite = 0x21,
|
||||||
LUT_BLACK_TO_WHITE = 0x22,
|
LutBlackToWhite = 0x22,
|
||||||
LUT_WHITE_TO_BLACK = 0x23,
|
LutWhiteToBlack = 0x23,
|
||||||
LUT_BLACK_TO_BLACK = 0x24,
|
LutBlackToBlack = 0x24,
|
||||||
|
|
||||||
PLL_CONTROL = 0x30,
|
PllControl = 0x30,
|
||||||
TEMPERATURE_SENSOR_COMMAND = 0x40,
|
TemperatureSensor = 0x40,
|
||||||
TEMPERATURE_SENSOR_SELECTION = 0x41,
|
TemperatureSensorSelection = 0x41,
|
||||||
VCOM_AND_DATA_INTERVAL_SETTING = 0x50,
|
VcomAndDataIntervalSetting = 0x50,
|
||||||
RESOLUTION_SETTING = 0x61,
|
ResolutionSetting = 0x61,
|
||||||
VCM_DC_SETTING = 0x82,
|
VcmDcSetting = 0x82,
|
||||||
POWER_SAVING = 0xE3,
|
PowerSaving = 0xE3,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl traits::Command for Command {
|
impl traits::Command for Command {
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@
|
||||||
//!# let mut delay = delay::MockNoop::new();
|
//!# let mut delay = delay::MockNoop::new();
|
||||||
//!
|
//!
|
||||||
//!// Setup EPD
|
//!// Setup EPD
|
||||||
//!let mut epd = EPD2in9bc::new(&mut spi, cs_pin, busy_in, dc, rst, &mut delay)?;
|
//!let mut epd = Epd2in9bc::new(&mut spi, cs_pin, busy_in, dc, rst, &mut delay)?;
|
||||||
//!
|
//!
|
||||||
//!// Use display graphics from embedded-graphics
|
//!// Use display graphics from embedded-graphics
|
||||||
//!// This display is for the black/white pixels
|
//!// This display is for the black/white pixels
|
||||||
|
|
@ -60,7 +60,7 @@ use embedded_hal::{
|
||||||
|
|
||||||
use crate::interface::DisplayInterface;
|
use crate::interface::DisplayInterface;
|
||||||
use crate::traits::{
|
use crate::traits::{
|
||||||
InternalWiAdditions, RefreshLUT, WaveshareDisplay, WaveshareThreeColorDisplay,
|
InternalWiAdditions, RefreshLut, WaveshareDisplay, WaveshareThreeColorDisplay,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Width of epd2in9bc in pixels
|
/// Width of epd2in9bc in pixels
|
||||||
|
|
@ -89,14 +89,14 @@ mod graphics;
|
||||||
#[cfg(feature = "graphics")]
|
#[cfg(feature = "graphics")]
|
||||||
pub use self::graphics::Display2in9bc;
|
pub use self::graphics::Display2in9bc;
|
||||||
|
|
||||||
/// EPD2in9bc driver
|
/// Epd2in9bc driver
|
||||||
pub struct EPD2in9bc<SPI, CS, BUSY, DC, RST> {
|
pub struct Epd2in9bc<SPI, CS, BUSY, DC, RST> {
|
||||||
interface: DisplayInterface<SPI, CS, BUSY, DC, RST>,
|
interface: DisplayInterface<SPI, CS, BUSY, DC, RST>,
|
||||||
color: Color,
|
color: Color,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<SPI, CS, BUSY, DC, RST> InternalWiAdditions<SPI, CS, BUSY, DC, RST>
|
impl<SPI, CS, BUSY, DC, RST> InternalWiAdditions<SPI, CS, BUSY, DC, RST>
|
||||||
for EPD2in9bc<SPI, CS, BUSY, DC, RST>
|
for Epd2in9bc<SPI, CS, BUSY, DC, RST>
|
||||||
where
|
where
|
||||||
SPI: Write<u8>,
|
SPI: Write<u8>,
|
||||||
CS: OutputPin,
|
CS: OutputPin,
|
||||||
|
|
@ -115,26 +115,26 @@ where
|
||||||
|
|
||||||
// start the booster
|
// start the booster
|
||||||
self.interface
|
self.interface
|
||||||
.cmd_with_data(spi, Command::BOOSTER_SOFT_START, &[0x17, 0x17, 0x17])?;
|
.cmd_with_data(spi, Command::BoosterSoftStart, &[0x17, 0x17, 0x17])?;
|
||||||
|
|
||||||
// power on
|
// power on
|
||||||
self.command(spi, Command::POWER_ON)?;
|
self.command(spi, Command::PowerOn)?;
|
||||||
delay.delay_ms(5);
|
delay.delay_ms(5);
|
||||||
self.wait_until_idle();
|
self.wait_until_idle();
|
||||||
|
|
||||||
// set the panel settings
|
// set the panel settings
|
||||||
self.cmd_with_data(spi, Command::PANEL_SETTING, &[0x8F])?;
|
self.cmd_with_data(spi, Command::PanelSetting, &[0x8F])?;
|
||||||
|
|
||||||
self.cmd_with_data(
|
self.cmd_with_data(
|
||||||
spi,
|
spi,
|
||||||
Command::VCOM_AND_DATA_INTERVAL_SETTING,
|
Command::VcomAndDataIntervalSetting,
|
||||||
&[WHITE_BORDER | VCOM_DATA_INTERVAL],
|
&[WHITE_BORDER | VCOM_DATA_INTERVAL],
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
// set resolution
|
// set resolution
|
||||||
self.send_resolution(spi)?;
|
self.send_resolution(spi)?;
|
||||||
|
|
||||||
self.cmd_with_data(spi, Command::VCM_DC_SETTING, &[0x0A])?;
|
self.cmd_with_data(spi, Command::VcmDcSetting, &[0x0A])?;
|
||||||
|
|
||||||
self.wait_until_idle();
|
self.wait_until_idle();
|
||||||
|
|
||||||
|
|
@ -143,7 +143,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<SPI, CS, BUSY, DC, RST> WaveshareThreeColorDisplay<SPI, CS, BUSY, DC, RST>
|
impl<SPI, CS, BUSY, DC, RST> WaveshareThreeColorDisplay<SPI, CS, BUSY, DC, RST>
|
||||||
for EPD2in9bc<SPI, CS, BUSY, DC, RST>
|
for Epd2in9bc<SPI, CS, BUSY, DC, RST>
|
||||||
where
|
where
|
||||||
SPI: Write<u8>,
|
SPI: Write<u8>,
|
||||||
CS: OutputPin,
|
CS: OutputPin,
|
||||||
|
|
@ -165,8 +165,7 @@ where
|
||||||
///
|
///
|
||||||
/// Finish by calling `update_chromatic_frame`.
|
/// Finish by calling `update_chromatic_frame`.
|
||||||
fn update_achromatic_frame(&mut self, spi: &mut SPI, black: &[u8]) -> Result<(), SPI::Error> {
|
fn update_achromatic_frame(&mut self, spi: &mut SPI, black: &[u8]) -> Result<(), SPI::Error> {
|
||||||
self.interface
|
self.interface.cmd(spi, Command::DataStartTransmission1)?;
|
||||||
.cmd(spi, Command::DATA_START_TRANSMISSION_1)?;
|
|
||||||
self.interface.data(spi, black)?;
|
self.interface.data(spi, black)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
@ -179,8 +178,7 @@ where
|
||||||
spi: &mut SPI,
|
spi: &mut SPI,
|
||||||
chromatic: &[u8],
|
chromatic: &[u8],
|
||||||
) -> Result<(), SPI::Error> {
|
) -> Result<(), SPI::Error> {
|
||||||
self.interface
|
self.interface.cmd(spi, Command::DataStartTransmission2)?;
|
||||||
.cmd(spi, Command::DATA_START_TRANSMISSION_2)?;
|
|
||||||
self.interface.data(spi, chromatic)?;
|
self.interface.data(spi, chromatic)?;
|
||||||
|
|
||||||
self.wait_until_idle();
|
self.wait_until_idle();
|
||||||
|
|
@ -189,7 +187,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<SPI, CS, BUSY, DC, RST> WaveshareDisplay<SPI, CS, BUSY, DC, RST>
|
impl<SPI, CS, BUSY, DC, RST> WaveshareDisplay<SPI, CS, BUSY, DC, RST>
|
||||||
for EPD2in9bc<SPI, CS, BUSY, DC, RST>
|
for Epd2in9bc<SPI, CS, BUSY, DC, RST>
|
||||||
where
|
where
|
||||||
SPI: Write<u8>,
|
SPI: Write<u8>,
|
||||||
CS: OutputPin,
|
CS: OutputPin,
|
||||||
|
|
@ -209,7 +207,7 @@ where
|
||||||
let interface = DisplayInterface::new(cs, busy, dc, rst);
|
let interface = DisplayInterface::new(cs, busy, dc, rst);
|
||||||
let color = DEFAULT_BACKGROUND_COLOR;
|
let color = DEFAULT_BACKGROUND_COLOR;
|
||||||
|
|
||||||
let mut epd = EPD2in9bc { interface, color };
|
let mut epd = Epd2in9bc { interface, color };
|
||||||
|
|
||||||
epd.init(spi, delay)?;
|
epd.init(spi, delay)?;
|
||||||
|
|
||||||
|
|
@ -220,15 +218,15 @@ where
|
||||||
// Section 8.2 from datasheet
|
// Section 8.2 from datasheet
|
||||||
self.interface.cmd_with_data(
|
self.interface.cmd_with_data(
|
||||||
spi,
|
spi,
|
||||||
Command::VCOM_AND_DATA_INTERVAL_SETTING,
|
Command::VcomAndDataIntervalSetting,
|
||||||
&[FLOATING_BORDER | VCOM_DATA_INTERVAL],
|
&[FLOATING_BORDER | VCOM_DATA_INTERVAL],
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
self.command(spi, Command::POWER_OFF)?;
|
self.command(spi, Command::PowerOff)?;
|
||||||
// The example STM code from Github has a wait after POWER_OFF
|
// The example STM code from Github has a wait after PowerOff
|
||||||
self.wait_until_idle();
|
self.wait_until_idle();
|
||||||
|
|
||||||
self.cmd_with_data(spi, Command::DEEP_SLEEP, &[0xA5])?;
|
self.cmd_with_data(spi, Command::DeepSleep, &[0xA5])?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
@ -258,16 +256,14 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_frame(&mut self, spi: &mut SPI, buffer: &[u8]) -> Result<(), SPI::Error> {
|
fn update_frame(&mut self, spi: &mut SPI, buffer: &[u8]) -> Result<(), SPI::Error> {
|
||||||
self.interface
|
self.interface.cmd(spi, Command::DataStartTransmission1)?;
|
||||||
.cmd(spi, Command::DATA_START_TRANSMISSION_1)?;
|
|
||||||
|
|
||||||
self.interface.data(spi, &buffer)?;
|
self.interface.data(spi, &buffer)?;
|
||||||
|
|
||||||
// Clear the chromatic layer
|
// Clear the chromatic layer
|
||||||
let color = self.color.get_byte_value();
|
let color = self.color.get_byte_value();
|
||||||
|
|
||||||
self.interface
|
self.interface.cmd(spi, Command::DataStartTransmission2)?;
|
||||||
.cmd(spi, Command::DATA_START_TRANSMISSION_2)?;
|
|
||||||
self.interface.data_x_times(spi, color, NUM_DISPLAY_BITS)?;
|
self.interface.data_x_times(spi, color, NUM_DISPLAY_BITS)?;
|
||||||
|
|
||||||
self.wait_until_idle();
|
self.wait_until_idle();
|
||||||
|
|
@ -288,7 +284,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
fn display_frame(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> {
|
fn display_frame(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> {
|
||||||
self.command(spi, Command::DISPLAY_REFRESH)?;
|
self.command(spi, Command::DisplayRefresh)?;
|
||||||
|
|
||||||
self.wait_until_idle();
|
self.wait_until_idle();
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
@ -306,14 +302,12 @@ where
|
||||||
let color = DEFAULT_BACKGROUND_COLOR.get_byte_value();
|
let color = DEFAULT_BACKGROUND_COLOR.get_byte_value();
|
||||||
|
|
||||||
// Clear the black
|
// Clear the black
|
||||||
self.interface
|
self.interface.cmd(spi, Command::DataStartTransmission1)?;
|
||||||
.cmd(spi, Command::DATA_START_TRANSMISSION_1)?;
|
|
||||||
|
|
||||||
self.interface.data_x_times(spi, color, NUM_DISPLAY_BITS)?;
|
self.interface.data_x_times(spi, color, NUM_DISPLAY_BITS)?;
|
||||||
|
|
||||||
// Clear the chromatic
|
// Clear the chromatic
|
||||||
self.interface
|
self.interface.cmd(spi, Command::DataStartTransmission2)?;
|
||||||
.cmd(spi, Command::DATA_START_TRANSMISSION_2)?;
|
|
||||||
self.interface.data_x_times(spi, color, NUM_DISPLAY_BITS)?;
|
self.interface.data_x_times(spi, color, NUM_DISPLAY_BITS)?;
|
||||||
|
|
||||||
self.wait_until_idle();
|
self.wait_until_idle();
|
||||||
|
|
@ -323,7 +317,7 @@ where
|
||||||
fn set_lut(
|
fn set_lut(
|
||||||
&mut self,
|
&mut self,
|
||||||
_spi: &mut SPI,
|
_spi: &mut SPI,
|
||||||
_refresh_rate: Option<RefreshLUT>,
|
_refresh_rate: Option<RefreshLut>,
|
||||||
) -> Result<(), SPI::Error> {
|
) -> Result<(), SPI::Error> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
@ -333,7 +327,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<SPI, CS, BUSY, DC, RST> EPD2in9bc<SPI, CS, BUSY, DC, RST>
|
impl<SPI, CS, BUSY, DC, RST> Epd2in9bc<SPI, CS, BUSY, DC, RST>
|
||||||
where
|
where
|
||||||
SPI: Write<u8>,
|
SPI: Write<u8>,
|
||||||
CS: OutputPin,
|
CS: OutputPin,
|
||||||
|
|
@ -366,7 +360,7 @@ where
|
||||||
let w = self.width();
|
let w = self.width();
|
||||||
let h = self.height();
|
let h = self.height();
|
||||||
|
|
||||||
self.command(spi, Command::RESOLUTION_SETTING)?;
|
self.command(spi, Command::ResolutionSetting)?;
|
||||||
|
|
||||||
self.send_data(spi, &[w as u8])?;
|
self.send_data(spi, &[w as u8])?;
|
||||||
self.send_data(spi, &[(h >> 8) as u8])?;
|
self.send_data(spi, &[(h >> 8) as u8])?;
|
||||||
|
|
@ -382,7 +376,7 @@ where
|
||||||
};
|
};
|
||||||
self.cmd_with_data(
|
self.cmd_with_data(
|
||||||
spi,
|
spi,
|
||||||
Command::VCOM_AND_DATA_INTERVAL_SETTING,
|
Command::VcomAndDataIntervalSetting,
|
||||||
&[border | VCOM_DATA_INTERVAL],
|
&[border | VCOM_DATA_INTERVAL],
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,6 @@ use crate::traits;
|
||||||
///
|
///
|
||||||
/// The description of the single commands is mostly taken from IL0398.pdf
|
/// The description of the single commands is mostly taken from IL0398.pdf
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[allow(non_camel_case_types)]
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
pub(crate) enum Command {
|
pub(crate) enum Command {
|
||||||
/// Set Resolution, LUT selection, BWR pixels, gate scan direction, source shift direction, booster switch, soft reset
|
/// Set Resolution, LUT selection, BWR pixels, gate scan direction, source shift direction, booster switch, soft reset
|
||||||
|
|
@ -17,142 +16,142 @@ pub(crate) enum Command {
|
||||||
/// 0x1F B/W Mode, LUT from OTP
|
/// 0x1F B/W Mode, LUT from OTP
|
||||||
/// 0x2F Red Mode, LUT set by registers
|
/// 0x2F Red Mode, LUT set by registers
|
||||||
/// 0x3F B/W Mode, LUT set by registers
|
/// 0x3F B/W Mode, LUT set by registers
|
||||||
PANEL_SETTING = 0x00,
|
PanelSetting = 0x00,
|
||||||
/// selecting internal and external power
|
/// selecting internal and external power
|
||||||
/// self.send_data(0x03)?; //VDS_EN, VDG_EN
|
/// self.send_data(0x03)?; //VDS_EN, VDG_EN
|
||||||
/// self.send_data(0x00)?; //VCOM_HV, VGHL_LV[1], VGHL_LV[0]
|
/// self.send_data(0x00)?; //VCOM_HV, VGHL_LV[1], VGHL_LV[0]
|
||||||
/// self.send_data(0x2b)?; //VDH
|
/// self.send_data(0x2b)?; //VDH
|
||||||
/// self.send_data(0x2b)?; //VDL
|
/// self.send_data(0x2b)?; //VDL
|
||||||
/// self.send_data(0xff)?; //VDHR
|
/// self.send_data(0xff)?; //VDHR
|
||||||
POWER_SETTING = 0x01,
|
PowerSetting = 0x01,
|
||||||
/// After the Power Off command, the driver will power off following the Power Off Sequence. This command will turn off charge
|
/// After the Power Off command, the driver will power off following the Power Off Sequence. This command will turn off charge
|
||||||
/// pump, T-con, source driver, gate driver, VCOM, and temperature sensor, but register data will be kept until VDD becomes OFF.
|
/// pump, T-con, source driver, gate driver, VCOM, and temperature sensor, but register data will be kept until VDD becomes OFF.
|
||||||
/// Source Driver output and Vcom will remain as previous condition, which may have 2 conditions: floating.
|
/// Source Driver output and Vcom will remain as previous condition, which may have 2 conditions: floating.
|
||||||
POWER_OFF = 0x02,
|
PowerOff = 0x02,
|
||||||
/// Setting Power OFF sequence
|
/// Setting Power OFF sequence
|
||||||
POWER_OFF_SEQUENCE_SETTING = 0x03,
|
PowerOffSequenceSetting = 0x03,
|
||||||
/// Turning On the Power
|
/// Turning On the Power
|
||||||
POWER_ON = 0x04,
|
PowerOn = 0x04,
|
||||||
/// This command enables the internal bandgap, which will be cleared by the next POF.
|
/// This command enables the internal bandgap, which will be cleared by the next POF.
|
||||||
POWER_ON_MEASURE = 0x05,
|
PowerOnMeasure = 0x05,
|
||||||
/// Starting data transmission
|
/// Starting data transmission
|
||||||
/// 3-times: self.send_data(0x17)?; //07 0f 17 1f 27 2F 37 2f
|
/// 3-times: self.send_data(0x17)?; //07 0f 17 1f 27 2F 37 2f
|
||||||
BOOSTER_SOFT_START = 0x06,
|
BoosterSoftStart = 0x06,
|
||||||
/// After this command is transmitted, the chip would enter the deep-sleep mode to save power.
|
/// After this command is transmitted, the chip would enter the deep-sleep mode to save power.
|
||||||
///
|
///
|
||||||
/// The deep sleep mode would return to standby by hardware reset.
|
/// The deep sleep mode would return to standby by hardware reset.
|
||||||
///
|
///
|
||||||
/// The only one parameter is a check code, the command would be excuted if check code = 0xA5.
|
/// The only one parameter is a check code, the command would be excuted if check code = 0xA5.
|
||||||
DEEP_SLEEP = 0x07,
|
DeepSleep = 0x07,
|
||||||
/// This command starts transmitting data and write them into SRAM. To complete data transmission, command DSP (Data
|
/// This command starts transmitting data and write them into SRAM. To complete data transmission, command DSP (Data
|
||||||
/// transmission Stop) must be issued. Then the chip will start to send data/VCOM for panel.
|
/// transmission Stop) must be issued. Then the chip will start to send data/VCOM for panel.
|
||||||
///
|
///
|
||||||
/// - In B/W mode, this command writes “OLD” data to SRAM.
|
/// - In B/W mode, this command writes “OLD” data to SRAM.
|
||||||
/// - In B/W/Red mode, this command writes “B/W” data to SRAM.
|
/// - In B/W/Red mode, this command writes “B/W” data to SRAM.
|
||||||
/// - In Program mode, this command writes “OTP” data to SRAM for programming.
|
/// - In Program mode, this command writes “OTP” data to SRAM for programming.
|
||||||
DATA_START_TRANSMISSION_1 = 0x10,
|
DataStartTransmission1 = 0x10,
|
||||||
/// Stopping data transmission
|
/// Stopping data transmission
|
||||||
DATA_STOP = 0x11,
|
DataStop = 0x11,
|
||||||
/// While user sent this command, driver will refresh display (data/VCOM) according to SRAM data and LUT.
|
/// While user sent this command, driver will refresh display (data/VCOM) according to SRAM data and LUT.
|
||||||
///
|
///
|
||||||
/// After Display Refresh command, BUSY_N signal will become “0” and the refreshing of panel starts.
|
/// After Display Refresh command, BUSY_N signal will become “0” and the refreshing of panel starts.
|
||||||
DISPLAY_REFRESH = 0x12,
|
DisplayRefresh = 0x12,
|
||||||
/// This command starts transmitting data and write them into SRAM. To complete data transmission, command DSP (Data
|
/// This command starts transmitting data and write them into SRAM. To complete data transmission, command DSP (Data
|
||||||
/// transmission Stop) must be issued. Then the chip will start to send data/VCOM for panel.
|
/// transmission Stop) must be issued. Then the chip will start to send data/VCOM for panel.
|
||||||
/// - In B/W mode, this command writes “NEW” data to SRAM.
|
/// - In B/W mode, this command writes “NEW” data to SRAM.
|
||||||
/// - In B/W/Red mode, this command writes “RED” data to SRAM.
|
/// - In B/W/Red mode, this command writes “RED” data to SRAM.
|
||||||
DATA_START_TRANSMISSION_2 = 0x13,
|
DataStartTransmission2 = 0x13,
|
||||||
|
|
||||||
/// This command stores VCOM Look-Up Table with 7 groups of data. Each group contains information for one state and is stored
|
/// This command stores VCOM Look-Up Table with 7 groups of data. Each group contains information for one state and is stored
|
||||||
/// with 6 bytes, while the sixth byte indicates how many times that phase will repeat.
|
/// with 6 bytes, while the sixth byte indicates how many times that phase will repeat.
|
||||||
///
|
///
|
||||||
/// from IL0373
|
/// from IL0373
|
||||||
LUT_FOR_VCOM = 0x20,
|
LutForVcom = 0x20,
|
||||||
/// This command stores White-to-White Look-Up Table with 7 groups of data. Each group contains information for one state and is
|
/// This command stores White-to-White Look-Up Table with 7 groups of data. Each group contains information for one state and is
|
||||||
/// stored with 6 bytes, while the sixth byte indicates how many times that phase will repeat.
|
/// stored with 6 bytes, while the sixth byte indicates how many times that phase will repeat.
|
||||||
///
|
///
|
||||||
/// from IL0373
|
/// from IL0373
|
||||||
LUT_WHITE_TO_WHITE = 0x21,
|
LutWhiteToWhite = 0x21,
|
||||||
/// This command stores Black-to-White Look-Up Table with 7 groups of data. Each group contains information for one state and is
|
/// This command stores Black-to-White Look-Up Table with 7 groups of data. Each group contains information for one state and is
|
||||||
/// stored with 6 bytes, while the sixth byte indicates how many times that phase will repeat.
|
/// stored with 6 bytes, while the sixth byte indicates how many times that phase will repeat.
|
||||||
///
|
///
|
||||||
/// from IL0373
|
/// from IL0373
|
||||||
LUT_BLACK_TO_WHITE = 0x22,
|
LutBlackToWhite = 0x22,
|
||||||
/// This command stores White-to-Black Look-Up Table with 7 groups of data. Each group contains information for one state and is
|
/// This command stores White-to-Black Look-Up Table with 7 groups of data. Each group contains information for one state and is
|
||||||
/// stored with 6 bytes, while the sixth byte indicates how many times that phase will repeat.
|
/// stored with 6 bytes, while the sixth byte indicates how many times that phase will repeat.
|
||||||
///
|
///
|
||||||
/// from IL0373
|
/// from IL0373
|
||||||
LUT_WHITE_TO_BLACK = 0x23,
|
LutWhiteToBlack = 0x23,
|
||||||
/// This command stores Black-to-Black Look-Up Table with 7 groups of data. Each group contains information for one state and is
|
/// This command stores Black-to-Black Look-Up Table with 7 groups of data. Each group contains information for one state and is
|
||||||
/// stored with 6 bytes, while the sixth byte indicates how many times that phase will repeat.
|
/// stored with 6 bytes, while the sixth byte indicates how many times that phase will repeat.
|
||||||
///
|
///
|
||||||
/// from IL0373
|
/// from IL0373
|
||||||
LUT_BLACK_TO_BLACK = 0x24,
|
LutBlackToBlack = 0x24,
|
||||||
/// The command controls the PLL clock frequency.
|
/// The command controls the PLL clock frequency.
|
||||||
PLL_CONTROL = 0x30,
|
PllControl = 0x30,
|
||||||
/// This command reads the temperature sensed by the temperature sensor.
|
/// This command reads the temperature sensed by the temperature sensor.
|
||||||
///
|
///
|
||||||
/// Doesn't work! Waveshare doesn't connect the read pin
|
/// Doesn't work! Waveshare doesn't connect the read pin
|
||||||
TEMPERATURE_SENSOR_COMMAND = 0x40,
|
TemperatureSensor = 0x40,
|
||||||
/// Selects the Internal or External temperature sensor and offset
|
/// Selects the Internal or External temperature sensor and offset
|
||||||
TEMPERATURE_SENSOR_SELECTION = 0x41,
|
TemperatureSensorSelection = 0x41,
|
||||||
/// Write External Temperature Sensor
|
/// Write External Temperature Sensor
|
||||||
TEMPERATURE_SENSOR_WRITE = 0x42,
|
TemperatureSensorWrite = 0x42,
|
||||||
/// Read External Temperature Sensor
|
/// Read External Temperature Sensor
|
||||||
///
|
///
|
||||||
/// Doesn't work! Waveshare doesn't connect the read pin
|
/// Doesn't work! Waveshare doesn't connect the read pin
|
||||||
TEMPERATURE_SENSOR_READ = 0x43,
|
TemperatureSensorRead = 0x43,
|
||||||
/// This command indicates the interval of Vcom and data output. When setting the vertical back porch, the total blanking will be kept (20 Hsync)
|
/// This command indicates the interval of Vcom and data output. When setting the vertical back porch, the total blanking will be kept (20 Hsync)
|
||||||
VCOM_AND_DATA_INTERVAL_SETTING = 0x50,
|
VcomAndDataIntervalSetting = 0x50,
|
||||||
/// This command indicates the input power condition. Host can read this flag to learn the battery condition.
|
/// This command indicates the input power condition. Host can read this flag to learn the battery condition.
|
||||||
LOW_POWER_DETECTION = 0x51,
|
LowPowerDetection = 0x51,
|
||||||
/// This command defines non-overlap period of Gate and Source.
|
/// This command defines non-overlap period of Gate and Source.
|
||||||
TCON_SETTING = 0x60,
|
TconSetting = 0x60,
|
||||||
/// This command defines alternative resolution and this setting is of higher priority than the RES\[1:0\] in R00H (PSR).
|
/// This command defines alternative resolution and this setting is of higher priority than the RES\[1:0\] in R00H (PSR).
|
||||||
RESOLUTION_SETTING = 0x61,
|
ResolutionSetting = 0x61,
|
||||||
/// This command defines the Fist Active Gate and First Active Source of active channels.
|
/// This command defines the Fist Active Gate and First Active Source of active channels.
|
||||||
GSST_SETTING = 0x65,
|
GsstSetting = 0x65,
|
||||||
/// The LUT_REV / Chip Revision is read from OTP address = 0x001.
|
/// The LUT_REV / Chip Revision is read from OTP address = 0x001.
|
||||||
///
|
///
|
||||||
/// Doesn't work! Waveshare doesn't connect the read pin
|
/// Doesn't work! Waveshare doesn't connect the read pin
|
||||||
REVISION = 0x70,
|
Revision = 0x70,
|
||||||
/// Read Flags. This command reads the IC status
|
/// Read Flags. This command reads the IC status
|
||||||
/// PTL, I2C_ERR, I2C_BUSY, DATA, PON, POF, BUSY
|
/// PTL, I2C_ERR, I2C_BUSY, DATA, PON, POF, BUSY
|
||||||
///
|
///
|
||||||
/// Doesn't work! Waveshare doesn't connect the read pin
|
/// Doesn't work! Waveshare doesn't connect the read pin
|
||||||
GET_STATUS = 0x71,
|
GetStatus = 0x71,
|
||||||
/// Automatically measure VCOM. This command reads the IC status
|
/// Automatically measure VCOM. This command reads the IC status
|
||||||
AUTO_MEASUREMENT_VCOM = 0x80,
|
AutoMeasurementVcom = 0x80,
|
||||||
/// This command gets the VCOM value
|
/// This command gets the VCOM value
|
||||||
///
|
///
|
||||||
/// Doesn't work! Waveshare doesn't connect the read pin
|
/// Doesn't work! Waveshare doesn't connect the read pin
|
||||||
READ_VCOM_VALUE = 0x81,
|
ReadVcomValue = 0x81,
|
||||||
/// Set VCM_DC
|
/// Set VCM_DC
|
||||||
VCM_DC_SETTING = 0x82,
|
VcmDcSetting = 0x82,
|
||||||
/// This command sets partial window
|
/// This command sets partial window
|
||||||
PARTIAL_WINDOW = 0x90,
|
PartialWindow = 0x90,
|
||||||
/// This command makes the display enter partial mode
|
/// This command makes the display enter partial mode
|
||||||
PARTIAL_IN = 0x91,
|
PartialIn = 0x91,
|
||||||
/// This command makes the display exit partial mode and enter normal mode
|
/// This command makes the display exit partial mode and enter normal mode
|
||||||
PARTIAL_OUT = 0x92,
|
PartialOut = 0x92,
|
||||||
/// After this command is issued, the chip would enter the program mode.
|
/// After this command is issued, the chip would enter the program mode.
|
||||||
///
|
///
|
||||||
/// After the programming procedure completed, a hardware reset is necessary for leaving program mode.
|
/// After the programming procedure completed, a hardware reset is necessary for leaving program mode.
|
||||||
///
|
///
|
||||||
/// The only one parameter is a check code, the command would be excuted if check code = 0xA5.
|
/// The only one parameter is a check code, the command would be excuted if check code = 0xA5.
|
||||||
PROGRAM_MODE = 0xA0,
|
ProgramMode = 0xA0,
|
||||||
/// After this command is transmitted, the programming state machine would be activated.
|
/// After this command is transmitted, the programming state machine would be activated.
|
||||||
///
|
///
|
||||||
/// The BUSY flag would fall to 0 until the programming is completed.
|
/// The BUSY flag would fall to 0 until the programming is completed.
|
||||||
ACTIVE_PROGRAMMING = 0xA1,
|
ActiveProgramming = 0xA1,
|
||||||
/// The command is used for reading the content of OTP for checking the data of programming.
|
/// The command is used for reading the content of OTP for checking the data of programming.
|
||||||
///
|
///
|
||||||
/// The value of (n) is depending on the amount of programmed data, tha max address = 0xFFF.
|
/// The value of (n) is depending on the amount of programmed data, tha max address = 0xFFF.
|
||||||
READ_OTP = 0xA2,
|
ReadOtp = 0xA2,
|
||||||
/// This command is set for saving power during fresh period. If the output voltage of VCOM / Source is from negative to positive or
|
/// This command is set for saving power during fresh period. If the output voltage of VCOM / Source is from negative to positive or
|
||||||
/// from positive to negative, the power saving mechanism will be activated. The active period width is defined by the following two
|
/// from positive to negative, the power saving mechanism will be activated. The active period width is defined by the following two
|
||||||
/// parameters.
|
/// parameters.
|
||||||
POWER_SAVING = 0xE3,
|
PowerSaving = 0xE3,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl traits::Command for Command {
|
impl traits::Command for Command {
|
||||||
|
|
@ -169,10 +168,10 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn command_addr() {
|
fn command_addr() {
|
||||||
assert_eq!(Command::POWER_SAVING.address(), 0xE3);
|
assert_eq!(Command::PowerSaving.address(), 0xE3);
|
||||||
|
|
||||||
assert_eq!(Command::PANEL_SETTING.address(), 0x00);
|
assert_eq!(Command::PanelSetting.address(), 0x00);
|
||||||
|
|
||||||
assert_eq!(Command::DISPLAY_REFRESH.address(), 0x12);
|
assert_eq!(Command::DisplayRefresh.address(), 0x12);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@
|
||||||
//!# let mut delay = delay::MockNoop::new();
|
//!# let mut delay = delay::MockNoop::new();
|
||||||
//!
|
//!
|
||||||
//!// Setup EPD
|
//!// Setup EPD
|
||||||
//!let mut epd = EPD4in2::new(&mut spi, cs_pin, busy_in, dc, rst, &mut delay)?;
|
//!let mut epd = Epd4in2::new(&mut spi, cs_pin, busy_in, dc, rst, &mut delay)?;
|
||||||
//!
|
//!
|
||||||
//!// Use display graphics from embedded-graphics
|
//!// Use display graphics from embedded-graphics
|
||||||
//!let mut display = Display4in2::default();
|
//!let mut display = Display4in2::default();
|
||||||
|
|
@ -55,7 +55,7 @@ use embedded_hal::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::interface::DisplayInterface;
|
use crate::interface::DisplayInterface;
|
||||||
use crate::traits::{InternalWiAdditions, QuickRefresh, RefreshLUT, WaveshareDisplay};
|
use crate::traits::{InternalWiAdditions, QuickRefresh, RefreshLut, WaveshareDisplay};
|
||||||
|
|
||||||
//The Lookup Tables for the Display
|
//The Lookup Tables for the Display
|
||||||
mod constants;
|
mod constants;
|
||||||
|
|
@ -79,19 +79,19 @@ mod graphics;
|
||||||
#[cfg(feature = "graphics")]
|
#[cfg(feature = "graphics")]
|
||||||
pub use self::graphics::Display4in2;
|
pub use self::graphics::Display4in2;
|
||||||
|
|
||||||
/// EPD4in2 driver
|
/// Epd4in2 driver
|
||||||
///
|
///
|
||||||
pub struct EPD4in2<SPI, CS, BUSY, DC, RST> {
|
pub struct Epd4in2<SPI, CS, BUSY, DC, RST> {
|
||||||
/// Connection Interface
|
/// Connection Interface
|
||||||
interface: DisplayInterface<SPI, CS, BUSY, DC, RST>,
|
interface: DisplayInterface<SPI, CS, BUSY, DC, RST>,
|
||||||
/// Background Color
|
/// Background Color
|
||||||
color: Color,
|
color: Color,
|
||||||
/// Refresh LUT
|
/// Refresh LUT
|
||||||
refresh: RefreshLUT,
|
refresh: RefreshLut,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<SPI, CS, BUSY, DC, RST> InternalWiAdditions<SPI, CS, BUSY, DC, RST>
|
impl<SPI, CS, BUSY, DC, RST> InternalWiAdditions<SPI, CS, BUSY, DC, RST>
|
||||||
for EPD4in2<SPI, CS, BUSY, DC, RST>
|
for Epd4in2<SPI, CS, BUSY, DC, RST>
|
||||||
where
|
where
|
||||||
SPI: Write<u8>,
|
SPI: Write<u8>,
|
||||||
CS: OutputPin,
|
CS: OutputPin,
|
||||||
|
|
@ -110,36 +110,36 @@ where
|
||||||
// set the power settings
|
// set the power settings
|
||||||
self.interface.cmd_with_data(
|
self.interface.cmd_with_data(
|
||||||
spi,
|
spi,
|
||||||
Command::POWER_SETTING,
|
Command::PowerSetting,
|
||||||
&[0x03, 0x00, 0x2b, 0x2b, 0xff],
|
&[0x03, 0x00, 0x2b, 0x2b, 0xff],
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
// start the booster
|
// start the booster
|
||||||
self.interface
|
self.interface
|
||||||
.cmd_with_data(spi, Command::BOOSTER_SOFT_START, &[0x17, 0x17, 0x17])?;
|
.cmd_with_data(spi, Command::BoosterSoftStart, &[0x17, 0x17, 0x17])?;
|
||||||
|
|
||||||
// power on
|
// power on
|
||||||
self.command(spi, Command::POWER_ON)?;
|
self.command(spi, Command::PowerOn)?;
|
||||||
delay.delay_ms(5);
|
delay.delay_ms(5);
|
||||||
self.wait_until_idle();
|
self.wait_until_idle();
|
||||||
|
|
||||||
// set the panel settings
|
// set the panel settings
|
||||||
self.cmd_with_data(spi, Command::PANEL_SETTING, &[0x3F])?;
|
self.cmd_with_data(spi, Command::PanelSetting, &[0x3F])?;
|
||||||
|
|
||||||
// Set Frequency, 200 Hz didn't work on my board
|
// Set Frequency, 200 Hz didn't work on my board
|
||||||
// 150Hz and 171Hz wasn't tested yet
|
// 150Hz and 171Hz wasn't tested yet
|
||||||
// TODO: Test these other frequencies
|
// TODO: Test these other frequencies
|
||||||
// 3A 100HZ 29 150Hz 39 200HZ 31 171HZ DEFAULT: 3c 50Hz
|
// 3A 100HZ 29 150Hz 39 200HZ 31 171HZ DEFAULT: 3c 50Hz
|
||||||
self.cmd_with_data(spi, Command::PLL_CONTROL, &[0x3A])?;
|
self.cmd_with_data(spi, Command::PllControl, &[0x3A])?;
|
||||||
|
|
||||||
self.send_resolution(spi)?;
|
self.send_resolution(spi)?;
|
||||||
|
|
||||||
self.interface
|
self.interface
|
||||||
.cmd_with_data(spi, Command::VCM_DC_SETTING, &[0x12])?;
|
.cmd_with_data(spi, Command::VcmDcSetting, &[0x12])?;
|
||||||
|
|
||||||
//VBDF 17|D7 VBDW 97 VBDB 57 VBDF F7 VBDW 77 VBDB 37 VBDR B7
|
//VBDF 17|D7 VBDW 97 VBDB 57 VBDF F7 VBDW 77 VBDB 37 VBDR B7
|
||||||
self.interface
|
self.interface
|
||||||
.cmd_with_data(spi, Command::VCOM_AND_DATA_INTERVAL_SETTING, &[0x97])?;
|
.cmd_with_data(spi, Command::VcomAndDataIntervalSetting, &[0x97])?;
|
||||||
|
|
||||||
self.set_lut(spi, None)?;
|
self.set_lut(spi, None)?;
|
||||||
|
|
||||||
|
|
@ -149,7 +149,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<SPI, CS, BUSY, DC, RST> WaveshareDisplay<SPI, CS, BUSY, DC, RST>
|
impl<SPI, CS, BUSY, DC, RST> WaveshareDisplay<SPI, CS, BUSY, DC, RST>
|
||||||
for EPD4in2<SPI, CS, BUSY, DC, RST>
|
for Epd4in2<SPI, CS, BUSY, DC, RST>
|
||||||
where
|
where
|
||||||
SPI: Write<u8>,
|
SPI: Write<u8>,
|
||||||
CS: OutputPin,
|
CS: OutputPin,
|
||||||
|
|
@ -169,10 +169,10 @@ where
|
||||||
let interface = DisplayInterface::new(cs, busy, dc, rst);
|
let interface = DisplayInterface::new(cs, busy, dc, rst);
|
||||||
let color = DEFAULT_BACKGROUND_COLOR;
|
let color = DEFAULT_BACKGROUND_COLOR;
|
||||||
|
|
||||||
let mut epd = EPD4in2 {
|
let mut epd = Epd4in2 {
|
||||||
interface,
|
interface,
|
||||||
color,
|
color,
|
||||||
refresh: RefreshLUT::FULL,
|
refresh: RefreshLut::Full,
|
||||||
};
|
};
|
||||||
|
|
||||||
epd.init(spi, delay)?;
|
epd.init(spi, delay)?;
|
||||||
|
|
@ -191,19 +191,19 @@ where
|
||||||
fn sleep(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> {
|
fn sleep(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> {
|
||||||
self.wait_until_idle();
|
self.wait_until_idle();
|
||||||
self.interface
|
self.interface
|
||||||
.cmd_with_data(spi, Command::VCOM_AND_DATA_INTERVAL_SETTING, &[0x17])?; //border floating
|
.cmd_with_data(spi, Command::VcomAndDataIntervalSetting, &[0x17])?; //border floating
|
||||||
self.command(spi, Command::VCM_DC_SETTING)?; // VCOM to 0V
|
self.command(spi, Command::VcmDcSetting)?; // VCOM to 0V
|
||||||
self.command(spi, Command::PANEL_SETTING)?;
|
self.command(spi, Command::PanelSetting)?;
|
||||||
|
|
||||||
self.command(spi, Command::POWER_SETTING)?; //VG&VS to 0V fast
|
self.command(spi, Command::PowerSetting)?; //VG&VS to 0V fast
|
||||||
for _ in 0..4 {
|
for _ in 0..4 {
|
||||||
self.send_data(spi, &[0x00])?;
|
self.send_data(spi, &[0x00])?;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.command(spi, Command::POWER_OFF)?;
|
self.command(spi, Command::PowerOff)?;
|
||||||
self.wait_until_idle();
|
self.wait_until_idle();
|
||||||
self.interface
|
self.interface
|
||||||
.cmd_with_data(spi, Command::DEEP_SLEEP, &[0xA5])?;
|
.cmd_with_data(spi, Command::DeepSleep, &[0xA5])?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -211,13 +211,12 @@ where
|
||||||
self.wait_until_idle();
|
self.wait_until_idle();
|
||||||
let color_value = self.color.get_byte_value();
|
let color_value = self.color.get_byte_value();
|
||||||
|
|
||||||
self.interface
|
self.interface.cmd(spi, Command::DataStartTransmission1)?;
|
||||||
.cmd(spi, Command::DATA_START_TRANSMISSION_1)?;
|
|
||||||
self.interface
|
self.interface
|
||||||
.data_x_times(spi, color_value, WIDTH / 8 * HEIGHT)?;
|
.data_x_times(spi, color_value, WIDTH / 8 * HEIGHT)?;
|
||||||
|
|
||||||
self.interface
|
self.interface
|
||||||
.cmd_with_data(spi, Command::DATA_START_TRANSMISSION_2, buffer)?;
|
.cmd_with_data(spi, Command::DataStartTransmission2, buffer)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -236,8 +235,8 @@ where
|
||||||
//return Err("Wrong buffersize");
|
//return Err("Wrong buffersize");
|
||||||
}
|
}
|
||||||
|
|
||||||
self.command(spi, Command::PARTIAL_IN)?;
|
self.command(spi, Command::PartialIn)?;
|
||||||
self.command(spi, Command::PARTIAL_WINDOW)?;
|
self.command(spi, Command::PartialWindow)?;
|
||||||
self.send_data(spi, &[(x >> 8) as u8])?;
|
self.send_data(spi, &[(x >> 8) as u8])?;
|
||||||
let tmp = x & 0xf8;
|
let tmp = x & 0xf8;
|
||||||
self.send_data(spi, &[tmp as u8])?; // x should be the multiple of 8, the last 3 bit will always be ignored
|
self.send_data(spi, &[tmp as u8])?; // x should be the multiple of 8, the last 3 bit will always be ignored
|
||||||
|
|
@ -256,26 +255,26 @@ where
|
||||||
//TODO: handle dtm somehow
|
//TODO: handle dtm somehow
|
||||||
let is_dtm1 = false;
|
let is_dtm1 = false;
|
||||||
if is_dtm1 {
|
if is_dtm1 {
|
||||||
self.command(spi, Command::DATA_START_TRANSMISSION_1)? //TODO: check if data_start transmission 1 also needs "old"/background data here
|
self.command(spi, Command::DataStartTransmission1)? //TODO: check if data_start transmission 1 also needs "old"/background data here
|
||||||
} else {
|
} else {
|
||||||
self.command(spi, Command::DATA_START_TRANSMISSION_2)?
|
self.command(spi, Command::DataStartTransmission2)?
|
||||||
}
|
}
|
||||||
|
|
||||||
self.send_data(spi, buffer)?;
|
self.send_data(spi, buffer)?;
|
||||||
|
|
||||||
self.command(spi, Command::PARTIAL_OUT)?;
|
self.command(spi, Command::PartialOut)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn display_frame(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> {
|
fn display_frame(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> {
|
||||||
self.wait_until_idle();
|
self.wait_until_idle();
|
||||||
self.command(spi, Command::DISPLAY_REFRESH)?;
|
self.command(spi, Command::DisplayRefresh)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_and_display_frame(&mut self, spi: &mut SPI, buffer: &[u8]) -> Result<(), SPI::Error> {
|
fn update_and_display_frame(&mut self, spi: &mut SPI, buffer: &[u8]) -> Result<(), SPI::Error> {
|
||||||
self.update_frame(spi, buffer)?;
|
self.update_frame(spi, buffer)?;
|
||||||
self.command(spi, Command::DISPLAY_REFRESH)?;
|
self.command(spi, Command::DisplayRefresh)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -285,13 +284,11 @@ where
|
||||||
|
|
||||||
let color_value = self.color.get_byte_value();
|
let color_value = self.color.get_byte_value();
|
||||||
|
|
||||||
self.interface
|
self.interface.cmd(spi, Command::DataStartTransmission1)?;
|
||||||
.cmd(spi, Command::DATA_START_TRANSMISSION_1)?;
|
|
||||||
self.interface
|
self.interface
|
||||||
.data_x_times(spi, color_value, WIDTH / 8 * HEIGHT)?;
|
.data_x_times(spi, color_value, WIDTH / 8 * HEIGHT)?;
|
||||||
|
|
||||||
self.interface
|
self.interface.cmd(spi, Command::DataStartTransmission2)?;
|
||||||
.cmd(spi, Command::DATA_START_TRANSMISSION_2)?;
|
|
||||||
self.interface
|
self.interface
|
||||||
.data_x_times(spi, color_value, WIDTH / 8 * HEIGHT)?;
|
.data_x_times(spi, color_value, WIDTH / 8 * HEIGHT)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
@ -316,16 +313,16 @@ where
|
||||||
fn set_lut(
|
fn set_lut(
|
||||||
&mut self,
|
&mut self,
|
||||||
spi: &mut SPI,
|
spi: &mut SPI,
|
||||||
refresh_rate: Option<RefreshLUT>,
|
refresh_rate: Option<RefreshLut>,
|
||||||
) -> Result<(), SPI::Error> {
|
) -> Result<(), SPI::Error> {
|
||||||
if let Some(refresh_lut) = refresh_rate {
|
if let Some(refresh_lut) = refresh_rate {
|
||||||
self.refresh = refresh_lut;
|
self.refresh = refresh_lut;
|
||||||
}
|
}
|
||||||
match self.refresh {
|
match self.refresh {
|
||||||
RefreshLUT::FULL => {
|
RefreshLut::Full => {
|
||||||
self.set_lut_helper(spi, &LUT_VCOM0, &LUT_WW, &LUT_BW, &LUT_WB, &LUT_BB)
|
self.set_lut_helper(spi, &LUT_VCOM0, &LUT_WW, &LUT_BW, &LUT_WB, &LUT_BB)
|
||||||
}
|
}
|
||||||
RefreshLUT::QUICK => self.set_lut_helper(
|
RefreshLut::Quick => self.set_lut_helper(
|
||||||
spi,
|
spi,
|
||||||
&LUT_VCOM0_QUICK,
|
&LUT_VCOM0_QUICK,
|
||||||
&LUT_WW_QUICK,
|
&LUT_WW_QUICK,
|
||||||
|
|
@ -341,7 +338,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<SPI, CS, BUSY, DC, RST> EPD4in2<SPI, CS, BUSY, DC, RST>
|
impl<SPI, CS, BUSY, DC, RST> Epd4in2<SPI, CS, BUSY, DC, RST>
|
||||||
where
|
where
|
||||||
SPI: Write<u8>,
|
SPI: Write<u8>,
|
||||||
CS: OutputPin,
|
CS: OutputPin,
|
||||||
|
|
@ -374,7 +371,7 @@ where
|
||||||
let w = self.width();
|
let w = self.width();
|
||||||
let h = self.height();
|
let h = self.height();
|
||||||
|
|
||||||
self.command(spi, Command::RESOLUTION_SETTING)?;
|
self.command(spi, Command::ResolutionSetting)?;
|
||||||
self.send_data(spi, &[(w >> 8) as u8])?;
|
self.send_data(spi, &[(w >> 8) as u8])?;
|
||||||
self.send_data(spi, &[w as u8])?;
|
self.send_data(spi, &[w as u8])?;
|
||||||
self.send_data(spi, &[(h >> 8) as u8])?;
|
self.send_data(spi, &[(h >> 8) as u8])?;
|
||||||
|
|
@ -392,19 +389,19 @@ where
|
||||||
) -> Result<(), SPI::Error> {
|
) -> Result<(), SPI::Error> {
|
||||||
self.wait_until_idle();
|
self.wait_until_idle();
|
||||||
// LUT VCOM
|
// LUT VCOM
|
||||||
self.cmd_with_data(spi, Command::LUT_FOR_VCOM, lut_vcom)?;
|
self.cmd_with_data(spi, Command::LutForVcom, lut_vcom)?;
|
||||||
|
|
||||||
// LUT WHITE to WHITE
|
// LUT WHITE to WHITE
|
||||||
self.cmd_with_data(spi, Command::LUT_WHITE_TO_WHITE, lut_ww)?;
|
self.cmd_with_data(spi, Command::LutWhiteToWhite, lut_ww)?;
|
||||||
|
|
||||||
// LUT BLACK to WHITE
|
// LUT BLACK to WHITE
|
||||||
self.cmd_with_data(spi, Command::LUT_BLACK_TO_WHITE, lut_bw)?;
|
self.cmd_with_data(spi, Command::LutBlackToWhite, lut_bw)?;
|
||||||
|
|
||||||
// LUT WHITE to BLACK
|
// LUT WHITE to BLACK
|
||||||
self.cmd_with_data(spi, Command::LUT_WHITE_TO_BLACK, lut_wb)?;
|
self.cmd_with_data(spi, Command::LutWhiteToBlack, lut_wb)?;
|
||||||
|
|
||||||
// LUT BLACK to BLACK
|
// LUT BLACK to BLACK
|
||||||
self.cmd_with_data(spi, Command::LUT_BLACK_TO_BLACK, lut_bb)?;
|
self.cmd_with_data(spi, Command::LutBlackToBlack, lut_bb)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -438,7 +435,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<SPI, CS, BUSY, DC, RST> QuickRefresh<SPI, CS, BUSY, DC, RST>
|
impl<SPI, CS, BUSY, DC, RST> QuickRefresh<SPI, CS, BUSY, DC, RST>
|
||||||
for EPD4in2<SPI, CS, BUSY, DC, RST>
|
for Epd4in2<SPI, CS, BUSY, DC, RST>
|
||||||
where
|
where
|
||||||
SPI: Write<u8>,
|
SPI: Write<u8>,
|
||||||
CS: OutputPin,
|
CS: OutputPin,
|
||||||
|
|
@ -450,8 +447,7 @@ where
|
||||||
fn update_old_frame(&mut self, spi: &mut SPI, buffer: &[u8]) -> Result<(), SPI::Error> {
|
fn update_old_frame(&mut self, spi: &mut SPI, buffer: &[u8]) -> Result<(), SPI::Error> {
|
||||||
self.wait_until_idle();
|
self.wait_until_idle();
|
||||||
|
|
||||||
self.interface
|
self.interface.cmd(spi, Command::DataStartTransmission1)?;
|
||||||
.cmd(spi, Command::DATA_START_TRANSMISSION_1)?;
|
|
||||||
|
|
||||||
self.interface.data(spi, buffer)?;
|
self.interface.data(spi, buffer)?;
|
||||||
|
|
||||||
|
|
@ -463,8 +459,7 @@ where
|
||||||
self.wait_until_idle();
|
self.wait_until_idle();
|
||||||
// self.send_resolution(spi)?;
|
// self.send_resolution(spi)?;
|
||||||
|
|
||||||
self.interface
|
self.interface.cmd(spi, Command::DataStartTransmission2)?;
|
||||||
.cmd(spi, Command::DATA_START_TRANSMISSION_2)?;
|
|
||||||
|
|
||||||
self.interface.data(spi, buffer)?;
|
self.interface.data(spi, buffer)?;
|
||||||
|
|
||||||
|
|
@ -487,13 +482,12 @@ where
|
||||||
//return Err("Wrong buffersize");
|
//return Err("Wrong buffersize");
|
||||||
}
|
}
|
||||||
|
|
||||||
self.interface.cmd(spi, Command::PARTIAL_IN)?;
|
self.interface.cmd(spi, Command::PartialIn)?;
|
||||||
self.interface.cmd(spi, Command::PARTIAL_WINDOW)?;
|
self.interface.cmd(spi, Command::PartialWindow)?;
|
||||||
|
|
||||||
self.shift_display(spi, x, y, width, height)?;
|
self.shift_display(spi, x, y, width, height)?;
|
||||||
|
|
||||||
self.interface
|
self.interface.cmd(spi, Command::DataStartTransmission1)?;
|
||||||
.cmd(spi, Command::DATA_START_TRANSMISSION_1)?;
|
|
||||||
|
|
||||||
self.interface.data(spi, buffer)?;
|
self.interface.data(spi, buffer)?;
|
||||||
|
|
||||||
|
|
@ -519,12 +513,11 @@ where
|
||||||
|
|
||||||
self.shift_display(spi, x, y, width, height)?;
|
self.shift_display(spi, x, y, width, height)?;
|
||||||
|
|
||||||
self.interface
|
self.interface.cmd(spi, Command::DataStartTransmission2)?;
|
||||||
.cmd(spi, Command::DATA_START_TRANSMISSION_2)?;
|
|
||||||
|
|
||||||
self.interface.data(spi, buffer)?;
|
self.interface.data(spi, buffer)?;
|
||||||
|
|
||||||
self.interface.cmd(spi, Command::PARTIAL_OUT)?;
|
self.interface.cmd(spi, Command::PartialOut)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -541,22 +534,20 @@ where
|
||||||
|
|
||||||
let color_value = self.color.get_byte_value();
|
let color_value = self.color.get_byte_value();
|
||||||
|
|
||||||
self.interface.cmd(spi, Command::PARTIAL_IN)?;
|
self.interface.cmd(spi, Command::PartialIn)?;
|
||||||
self.interface.cmd(spi, Command::PARTIAL_WINDOW)?;
|
self.interface.cmd(spi, Command::PartialWindow)?;
|
||||||
|
|
||||||
self.shift_display(spi, x, y, width, height)?;
|
self.shift_display(spi, x, y, width, height)?;
|
||||||
|
|
||||||
self.interface
|
self.interface.cmd(spi, Command::DataStartTransmission1)?;
|
||||||
.cmd(spi, Command::DATA_START_TRANSMISSION_1)?;
|
|
||||||
self.interface
|
self.interface
|
||||||
.data_x_times(spi, color_value, width / 8 * height)?;
|
.data_x_times(spi, color_value, width / 8 * height)?;
|
||||||
|
|
||||||
self.interface
|
self.interface.cmd(spi, Command::DataStartTransmission2)?;
|
||||||
.cmd(spi, Command::DATA_START_TRANSMISSION_2)?;
|
|
||||||
self.interface
|
self.interface
|
||||||
.data_x_times(spi, color_value, width / 8 * height)?;
|
.data_x_times(spi, color_value, width / 8 * height)?;
|
||||||
|
|
||||||
self.interface.cmd(spi, Command::PARTIAL_OUT)?;
|
self.interface.cmd(spi, Command::PartialOut)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,127 +8,126 @@ use crate::traits;
|
||||||
///
|
///
|
||||||
/// For more infos about the addresses and what they are doing look into the PDFs.
|
/// For more infos about the addresses and what they are doing look into the PDFs.
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[allow(non_camel_case_types)]
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
pub(crate) enum Command {
|
pub(crate) enum Command {
|
||||||
/// Set Resolution, LUT selection, BWR pixels, gate scan direction, source shift
|
/// Set Resolution, LUT selection, BWR pixels, gate scan direction, source shift
|
||||||
/// direction, booster switch, soft reset.
|
/// direction, booster switch, soft reset.
|
||||||
PANEL_SETTING = 0x00,
|
PanelSetting = 0x00,
|
||||||
|
|
||||||
/// Selecting internal and external power
|
/// Selecting internal and external power
|
||||||
POWER_SETTING = 0x01,
|
PowerSetting = 0x01,
|
||||||
|
|
||||||
/// After the Power Off command, the driver will power off following the Power Off
|
/// After the Power Off command, the driver will power off following the Power Off
|
||||||
/// Sequence; BUSY signal will become "0". This command will turn off charge pump,
|
/// Sequence; BUSY signal will become "0". This command will turn off charge pump,
|
||||||
/// T-con, source driver, gate driver, VCOM, and temperature sensor, but register
|
/// T-con, source driver, gate driver, VCOM, and temperature sensor, but register
|
||||||
/// data will be kept until VDD becomes OFF. Source Driver output and Vcom will remain
|
/// data will be kept until VDD becomes OFF. Source Driver output and Vcom will remain
|
||||||
/// as previous condition, which may have 2 conditions: 0V or floating.
|
/// as previous condition, which may have 2 conditions: 0V or floating.
|
||||||
POWER_OFF = 0x02,
|
PowerOff = 0x02,
|
||||||
|
|
||||||
/// Setting Power OFF sequence
|
/// Setting Power OFF sequence
|
||||||
POWER_OFF_SEQUENCE_SETTING = 0x03,
|
PowerOffSequenceSetting = 0x03,
|
||||||
|
|
||||||
/// Turning On the Power
|
/// Turning On the Power
|
||||||
///
|
///
|
||||||
/// After the Power ON command, the driver will power on following the Power ON
|
/// After the Power ON command, the driver will power on following the Power ON
|
||||||
/// sequence. Once complete, the BUSY signal will become "1".
|
/// sequence. Once complete, the BUSY signal will become "1".
|
||||||
POWER_ON = 0x04,
|
PowerOn = 0x04,
|
||||||
|
|
||||||
/// Starting data transmission
|
/// Starting data transmission
|
||||||
BOOSTER_SOFT_START = 0x06,
|
BoosterSoftStart = 0x06,
|
||||||
|
|
||||||
/// This command makes the chip enter the deep-sleep mode to save power.
|
/// This command makes the chip enter the deep-sleep mode to save power.
|
||||||
///
|
///
|
||||||
/// The deep sleep mode would return to stand-by by hardware reset.
|
/// The deep sleep mode would return to stand-by by hardware reset.
|
||||||
///
|
///
|
||||||
/// The only one parameter is a check code, the command would be excuted if check code = 0xA5.
|
/// The only one parameter is a check code, the command would be excuted if check code = 0xA5.
|
||||||
DEEP_SLEEP = 0x07,
|
DeepSleep = 0x07,
|
||||||
|
|
||||||
/// This command starts transmitting data and write them into SRAM. To complete data
|
/// This command starts transmitting data and write them into SRAM. To complete data
|
||||||
/// transmission, command DSP (Data Stop) must be issued. Then the chip will start to
|
/// transmission, command DSP (Data Stop) must be issued. Then the chip will start to
|
||||||
/// send data/VCOM for panel.
|
/// send data/VCOM for panel.
|
||||||
///
|
///
|
||||||
/// BLACK/WHITE or OLD_DATA
|
/// BLACK/WHITE or OLD_DATA
|
||||||
DATA_START_TRANSMISSION_1 = 0x10,
|
DataStartTransmission1 = 0x10,
|
||||||
|
|
||||||
/// To stop data transmission, this command must be issued to check the `data_flag`.
|
/// To stop data transmission, this command must be issued to check the `data_flag`.
|
||||||
///
|
///
|
||||||
/// After this command, BUSY signal will become "0" until the display update is
|
/// After this command, BUSY signal will become "0" until the display update is
|
||||||
/// finished.
|
/// finished.
|
||||||
DATA_STOP = 0x11,
|
DataStop = 0x11,
|
||||||
|
|
||||||
/// After this command is issued, driver will refresh display (data/VCOM) according to
|
/// After this command is issued, driver will refresh display (data/VCOM) according to
|
||||||
/// SRAM data and LUT.
|
/// SRAM data and LUT.
|
||||||
///
|
///
|
||||||
/// After Display Refresh command, BUSY signal will become "0" until the display
|
/// After Display Refresh command, BUSY signal will become "0" until the display
|
||||||
/// update is finished.
|
/// update is finished.
|
||||||
DISPLAY_REFRESH = 0x12,
|
DisplayRefresh = 0x12,
|
||||||
|
|
||||||
/// Image Process Command
|
/// Image Process Command
|
||||||
IMAGE_PROCESS_COMMAND = 0x13,
|
ImageProcess = 0x13,
|
||||||
|
|
||||||
/// This command builds the VCOM Look-Up Table (LUTC).
|
/// This command builds the VCOM Look-Up Table (LUTC).
|
||||||
LUT_FOR_VCOM = 0x20,
|
LutForVcom = 0x20,
|
||||||
/// This command builds the Black Look-Up Table (LUTB).
|
/// This command builds the Black Look-Up Table (LUTB).
|
||||||
LUT_BLACK = 0x21,
|
LutBlack = 0x21,
|
||||||
/// This command builds the White Look-Up Table (LUTW).
|
/// This command builds the White Look-Up Table (LUTW).
|
||||||
LUT_WHITE = 0x22,
|
LutWhite = 0x22,
|
||||||
/// This command builds the Gray1 Look-Up Table (LUTG1).
|
/// This command builds the Gray1 Look-Up Table (LUTG1).
|
||||||
LUT_GRAY_1 = 0x23,
|
LutGray1 = 0x23,
|
||||||
/// This command builds the Gray2 Look-Up Table (LUTG2).
|
/// This command builds the Gray2 Look-Up Table (LUTG2).
|
||||||
LUT_GRAY_2 = 0x24,
|
LutGray2 = 0x24,
|
||||||
/// This command builds the Red0 Look-Up Table (LUTR0).
|
/// This command builds the Red0 Look-Up Table (LUTR0).
|
||||||
LUT_RED_0 = 0x25,
|
LutRed0 = 0x25,
|
||||||
/// This command builds the Red1 Look-Up Table (LUTR1).
|
/// This command builds the Red1 Look-Up Table (LUTR1).
|
||||||
LUT_RED_1 = 0x26,
|
LutRed1 = 0x26,
|
||||||
/// This command builds the Red2 Look-Up Table (LUTR2).
|
/// This command builds the Red2 Look-Up Table (LUTR2).
|
||||||
LUT_RED_2 = 0x27,
|
LutRed2 = 0x27,
|
||||||
/// This command builds the Red3 Look-Up Table (LUTR3).
|
/// This command builds the Red3 Look-Up Table (LUTR3).
|
||||||
LUT_RED_3 = 0x28,
|
LutRed3 = 0x28,
|
||||||
/// This command builds the XON Look-Up Table (LUTXON).
|
/// This command builds the XON Look-Up Table (LUTXON).
|
||||||
LUT_XON = 0x29,
|
LutXon = 0x29,
|
||||||
|
|
||||||
/// The command controls the PLL clock frequency.
|
/// The command controls the PLL clock frequency.
|
||||||
PLL_CONTROL = 0x30,
|
PllControl = 0x30,
|
||||||
|
|
||||||
/// This command reads the temperature sensed by the temperature sensor.
|
/// This command reads the temperature sensed by the temperature sensor.
|
||||||
TEMPERATURE_SENSOR_COMMAND = 0x40,
|
TemperatureSensor = 0x40,
|
||||||
/// This command selects the Internal or External temperature sensor.
|
/// This command selects the Internal or External temperature sensor.
|
||||||
TEMPERATURE_CALIBRATION = 0x41,
|
TemperatureCalibration = 0x41,
|
||||||
/// This command could write data to the external temperature sensor.
|
/// This command could write data to the external temperature sensor.
|
||||||
TEMPERATURE_SENSOR_WRITE = 0x42,
|
TemperatureSensorWrite = 0x42,
|
||||||
/// This command could read data from the external temperature sensor.
|
/// This command could read data from the external temperature sensor.
|
||||||
TEMPERATURE_SENSOR_READ = 0x43,
|
TemperatureSensorRead = 0x43,
|
||||||
|
|
||||||
/// This command indicates the interval of Vcom and data output. When setting the
|
/// This command indicates the interval of Vcom and data output. When setting the
|
||||||
/// vertical back porch, the total blanking will be kept (20 Hsync).
|
/// vertical back porch, the total blanking will be kept (20 Hsync).
|
||||||
VCOM_AND_DATA_INTERVAL_SETTING = 0x50,
|
VcomAndDataIntervalSetting = 0x50,
|
||||||
/// This command indicates the input power condition. Host can read this flag to learn
|
/// This command indicates the input power condition. Host can read this flag to learn
|
||||||
/// the battery condition.
|
/// the battery condition.
|
||||||
LOW_POWER_DETECTION = 0x51,
|
LowPowerDetection = 0x51,
|
||||||
|
|
||||||
/// This command defines non-overlap period of Gate and Source.
|
/// This command defines non-overlap period of Gate and Source.
|
||||||
TCON_SETTING = 0x60,
|
TconSetting = 0x60,
|
||||||
/// This command defines alternative resolution and this setting is of higher priority
|
/// This command defines alternative resolution and this setting is of higher priority
|
||||||
/// than the RES\[1:0\] in R00H (PSR).
|
/// than the RES\[1:0\] in R00H (PSR).
|
||||||
TCON_RESOLUTION = 0x61,
|
TconResolution = 0x61,
|
||||||
/// This command defines MCU host direct access external memory mode.
|
/// This command defines MCU host direct access external memory mode.
|
||||||
//SPI_FLASH_CONTROL = 0x65,
|
//SpiFlashControl = 0x65,
|
||||||
|
|
||||||
/// The LUT_REV / Chip Revision is read from OTP address = 25001 and 25000.
|
/// The LUT_REV / Chip Revision is read from OTP address = 25001 and 25000.
|
||||||
//REVISION = 0x70,
|
//Revision = 0x70,
|
||||||
/// This command reads the IC status.
|
/// This command reads the IC status.
|
||||||
GET_STATUS = 0x71,
|
GetStatus = 0x71,
|
||||||
|
|
||||||
/// This command implements related VCOM sensing setting.
|
/// This command implements related VCOM sensing setting.
|
||||||
//AUTO_MEASUREMENT_VCOM = 0x80,
|
//AutoMeasurementVcom = 0x80,
|
||||||
/// This command gets the VCOM value.
|
/// This command gets the VCOM value.
|
||||||
READ_VCOM_VALUE = 0x81,
|
ReadVcomValue = 0x81,
|
||||||
/// This command sets `VCOM_DC` value.
|
/// This command sets `VCOM_DC` value.
|
||||||
VCM_DC_SETTING = 0x82,
|
VcmDcSetting = 0x82,
|
||||||
// /// This is in all the Waveshare controllers for EPD6in65f, but it's not documented
|
// /// This is in all the Waveshare controllers for EPD6in65f, but it's not documented
|
||||||
// /// anywhere in the datasheet `¯\_(ツ)_/¯`
|
// /// anywhere in the datasheet `¯\_(ツ)_/¯`
|
||||||
FLASH_MODE = 0xE3,
|
FlashMode = 0xE3,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl traits::Command for Command {
|
impl traits::Command for Command {
|
||||||
|
|
@ -145,7 +144,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn command_addr() {
|
fn command_addr() {
|
||||||
assert_eq!(Command::PANEL_SETTING.address(), 0x00);
|
assert_eq!(Command::PanelSetting.address(), 0x00);
|
||||||
assert_eq!(Command::DISPLAY_REFRESH.address(), 0x12);
|
assert_eq!(Command::DisplayRefresh.address(), 0x12);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ use embedded_hal::{
|
||||||
|
|
||||||
use crate::color::OctColor;
|
use crate::color::OctColor;
|
||||||
use crate::interface::DisplayInterface;
|
use crate::interface::DisplayInterface;
|
||||||
use crate::traits::{InternalWiAdditions, RefreshLUT, WaveshareDisplay};
|
use crate::traits::{InternalWiAdditions, RefreshLut, WaveshareDisplay};
|
||||||
|
|
||||||
pub(crate) mod command;
|
pub(crate) mod command;
|
||||||
use self::command::Command;
|
use self::command::Command;
|
||||||
|
|
@ -31,9 +31,9 @@ pub const HEIGHT: u32 = 448;
|
||||||
pub const DEFAULT_BACKGROUND_COLOR: OctColor = OctColor::White;
|
pub const DEFAULT_BACKGROUND_COLOR: OctColor = OctColor::White;
|
||||||
const IS_BUSY_LOW: bool = true;
|
const IS_BUSY_LOW: bool = true;
|
||||||
|
|
||||||
/// EPD5in65f driver
|
/// Epd5in65f driver
|
||||||
///
|
///
|
||||||
pub struct EPD5in65f<SPI, CS, BUSY, DC, RST> {
|
pub struct Epd5in65f<SPI, CS, BUSY, DC, RST> {
|
||||||
/// Connection Interface
|
/// Connection Interface
|
||||||
interface: DisplayInterface<SPI, CS, BUSY, DC, RST>,
|
interface: DisplayInterface<SPI, CS, BUSY, DC, RST>,
|
||||||
/// Background Color
|
/// Background Color
|
||||||
|
|
@ -41,7 +41,7 @@ pub struct EPD5in65f<SPI, CS, BUSY, DC, RST> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<SPI, CS, BUSY, DC, RST> InternalWiAdditions<SPI, CS, BUSY, DC, RST>
|
impl<SPI, CS, BUSY, DC, RST> InternalWiAdditions<SPI, CS, BUSY, DC, RST>
|
||||||
for EPD5in65f<SPI, CS, BUSY, DC, RST>
|
for Epd5in65f<SPI, CS, BUSY, DC, RST>
|
||||||
where
|
where
|
||||||
SPI: Write<u8>,
|
SPI: Write<u8>,
|
||||||
CS: OutputPin,
|
CS: OutputPin,
|
||||||
|
|
@ -57,27 +57,27 @@ where
|
||||||
// Reset the device
|
// Reset the device
|
||||||
self.interface.reset(delay, 2);
|
self.interface.reset(delay, 2);
|
||||||
|
|
||||||
self.cmd_with_data(spi, Command::PANEL_SETTING, &[0xEF, 0x08])?;
|
self.cmd_with_data(spi, Command::PanelSetting, &[0xEF, 0x08])?;
|
||||||
self.cmd_with_data(spi, Command::POWER_SETTING, &[0x37, 0x00, 0x23, 0x23])?;
|
self.cmd_with_data(spi, Command::PowerSetting, &[0x37, 0x00, 0x23, 0x23])?;
|
||||||
self.cmd_with_data(spi, Command::POWER_OFF_SEQUENCE_SETTING, &[0x00])?;
|
self.cmd_with_data(spi, Command::PowerOffSequenceSetting, &[0x00])?;
|
||||||
self.cmd_with_data(spi, Command::BOOSTER_SOFT_START, &[0xC7, 0xC7, 0x1D])?;
|
self.cmd_with_data(spi, Command::BoosterSoftStart, &[0xC7, 0xC7, 0x1D])?;
|
||||||
self.cmd_with_data(spi, Command::PLL_CONTROL, &[0x3C])?;
|
self.cmd_with_data(spi, Command::PllControl, &[0x3C])?;
|
||||||
self.cmd_with_data(spi, Command::TEMPERATURE_SENSOR_COMMAND, &[0x00])?;
|
self.cmd_with_data(spi, Command::TemperatureSensor, &[0x00])?;
|
||||||
self.cmd_with_data(spi, Command::VCOM_AND_DATA_INTERVAL_SETTING, &[0x37])?;
|
self.cmd_with_data(spi, Command::VcomAndDataIntervalSetting, &[0x37])?;
|
||||||
self.cmd_with_data(spi, Command::TCON_SETTING, &[0x22])?;
|
self.cmd_with_data(spi, Command::TconSetting, &[0x22])?;
|
||||||
self.send_resolution(spi)?;
|
self.send_resolution(spi)?;
|
||||||
|
|
||||||
self.cmd_with_data(spi, Command::FLASH_MODE, &[0xAA])?;
|
self.cmd_with_data(spi, Command::FlashMode, &[0xAA])?;
|
||||||
|
|
||||||
delay.delay_ms(100);
|
delay.delay_ms(100);
|
||||||
|
|
||||||
self.cmd_with_data(spi, Command::VCOM_AND_DATA_INTERVAL_SETTING, &[0x37])?;
|
self.cmd_with_data(spi, Command::VcomAndDataIntervalSetting, &[0x37])?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<SPI, CS, BUSY, DC, RST> WaveshareDisplay<SPI, CS, BUSY, DC, RST>
|
impl<SPI, CS, BUSY, DC, RST> WaveshareDisplay<SPI, CS, BUSY, DC, RST>
|
||||||
for EPD5in65f<SPI, CS, BUSY, DC, RST>
|
for Epd5in65f<SPI, CS, BUSY, DC, RST>
|
||||||
where
|
where
|
||||||
SPI: Write<u8>,
|
SPI: Write<u8>,
|
||||||
CS: OutputPin,
|
CS: OutputPin,
|
||||||
|
|
@ -97,7 +97,7 @@ where
|
||||||
let interface = DisplayInterface::new(cs, busy, dc, rst);
|
let interface = DisplayInterface::new(cs, busy, dc, rst);
|
||||||
let color = DEFAULT_BACKGROUND_COLOR;
|
let color = DEFAULT_BACKGROUND_COLOR;
|
||||||
|
|
||||||
let mut epd = EPD5in65f { interface, color };
|
let mut epd = Epd5in65f { interface, color };
|
||||||
|
|
||||||
epd.init(spi, delay)?;
|
epd.init(spi, delay)?;
|
||||||
|
|
||||||
|
|
@ -113,14 +113,14 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sleep(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> {
|
fn sleep(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> {
|
||||||
self.cmd_with_data(spi, Command::DEEP_SLEEP, &[0xA5])?;
|
self.cmd_with_data(spi, Command::DeepSleep, &[0xA5])?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_frame(&mut self, spi: &mut SPI, buffer: &[u8]) -> Result<(), SPI::Error> {
|
fn update_frame(&mut self, spi: &mut SPI, buffer: &[u8]) -> Result<(), SPI::Error> {
|
||||||
self.wait_busy_high();
|
self.wait_busy_high();
|
||||||
self.send_resolution(spi)?;
|
self.send_resolution(spi)?;
|
||||||
self.cmd_with_data(spi, Command::DATA_START_TRANSMISSION_1, buffer)?;
|
self.cmd_with_data(spi, Command::DataStartTransmission1, buffer)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -138,11 +138,11 @@ where
|
||||||
|
|
||||||
fn display_frame(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> {
|
fn display_frame(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> {
|
||||||
self.wait_busy_high();
|
self.wait_busy_high();
|
||||||
self.command(spi, Command::POWER_ON)?;
|
self.command(spi, Command::PowerOn)?;
|
||||||
self.wait_busy_high();
|
self.wait_busy_high();
|
||||||
self.command(spi, Command::DISPLAY_REFRESH)?;
|
self.command(spi, Command::DisplayRefresh)?;
|
||||||
self.wait_busy_high();
|
self.wait_busy_high();
|
||||||
self.command(spi, Command::POWER_OFF)?;
|
self.command(spi, Command::PowerOff)?;
|
||||||
self.wait_busy_low();
|
self.wait_busy_low();
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
@ -157,7 +157,7 @@ where
|
||||||
let bg = OctColor::colors_byte(self.color, self.color);
|
let bg = OctColor::colors_byte(self.color, self.color);
|
||||||
self.wait_busy_high();
|
self.wait_busy_high();
|
||||||
self.send_resolution(spi)?;
|
self.send_resolution(spi)?;
|
||||||
self.command(spi, Command::DATA_START_TRANSMISSION_1)?;
|
self.command(spi, Command::DataStartTransmission1)?;
|
||||||
self.interface.data_x_times(spi, bg, WIDTH * HEIGHT / 2)?;
|
self.interface.data_x_times(spi, bg, WIDTH * HEIGHT / 2)?;
|
||||||
self.display_frame(spi)?;
|
self.display_frame(spi)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
@ -182,7 +182,7 @@ where
|
||||||
fn set_lut(
|
fn set_lut(
|
||||||
&mut self,
|
&mut self,
|
||||||
_spi: &mut SPI,
|
_spi: &mut SPI,
|
||||||
_refresh_rate: Option<RefreshLUT>,
|
_refresh_rate: Option<RefreshLut>,
|
||||||
) -> Result<(), SPI::Error> {
|
) -> Result<(), SPI::Error> {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
@ -192,7 +192,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<SPI, CS, BUSY, DC, RST> EPD5in65f<SPI, CS, BUSY, DC, RST>
|
impl<SPI, CS, BUSY, DC, RST> Epd5in65f<SPI, CS, BUSY, DC, RST>
|
||||||
where
|
where
|
||||||
SPI: Write<u8>,
|
SPI: Write<u8>,
|
||||||
CS: OutputPin,
|
CS: OutputPin,
|
||||||
|
|
@ -227,7 +227,7 @@ where
|
||||||
let w = self.width();
|
let w = self.width();
|
||||||
let h = self.height();
|
let h = self.height();
|
||||||
|
|
||||||
self.command(spi, Command::TCON_RESOLUTION)?;
|
self.command(spi, Command::TconResolution)?;
|
||||||
self.send_data(spi, &[(w >> 8) as u8])?;
|
self.send_data(spi, &[(w >> 8) as u8])?;
|
||||||
self.send_data(spi, &[w as u8])?;
|
self.send_data(spi, &[w as u8])?;
|
||||||
self.send_data(spi, &[(h >> 8) as u8])?;
|
self.send_data(spi, &[(h >> 8) as u8])?;
|
||||||
|
|
|
||||||
|
|
@ -2,136 +2,135 @@
|
||||||
|
|
||||||
use crate::traits;
|
use crate::traits;
|
||||||
|
|
||||||
/// EPD7in5 commands
|
/// Epd7in5 commands
|
||||||
///
|
///
|
||||||
/// Should rarely (never?) be needed directly.
|
/// Should rarely (never?) be needed directly.
|
||||||
///
|
///
|
||||||
/// For more infos about the addresses and what they are doing look into the PDFs.
|
/// For more infos about the addresses and what they are doing look into the PDFs.
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[allow(non_camel_case_types)]
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
pub(crate) enum Command {
|
pub(crate) enum Command {
|
||||||
/// Set Resolution, LUT selection, BWR pixels, gate scan direction, source shift
|
/// Set Resolution, LUT selection, BWR pixels, gate scan direction, source shift
|
||||||
/// direction, booster switch, soft reset.
|
/// direction, booster switch, soft reset.
|
||||||
PANEL_SETTING = 0x00,
|
PanelSetting = 0x00,
|
||||||
|
|
||||||
/// Selecting internal and external power
|
/// Selecting internal and external power
|
||||||
POWER_SETTING = 0x01,
|
PowerSetting = 0x01,
|
||||||
|
|
||||||
/// After the Power Off command, the driver will power off following the Power Off
|
/// After the Power Off command, the driver will power off following the Power Off
|
||||||
/// Sequence; BUSY signal will become "0". This command will turn off charge pump,
|
/// Sequence; BUSY signal will become "0". This command will turn off charge pump,
|
||||||
/// T-con, source driver, gate driver, VCOM, and temperature sensor, but register
|
/// T-con, source driver, gate driver, VCOM, and temperature sensor, but register
|
||||||
/// data will be kept until VDD becomes OFF. Source Driver output and Vcom will remain
|
/// data will be kept until VDD becomes OFF. Source Driver output and Vcom will remain
|
||||||
/// as previous condition, which may have 2 conditions: 0V or floating.
|
/// as previous condition, which may have 2 conditions: 0V or floating.
|
||||||
POWER_OFF = 0x02,
|
PowerOff = 0x02,
|
||||||
|
|
||||||
/// Setting Power OFF sequence
|
/// Setting Power OFF sequence
|
||||||
POWER_OFF_SEQUENCE_SETTING = 0x03,
|
PowerOffSequenceSetting = 0x03,
|
||||||
|
|
||||||
/// Turning On the Power
|
/// Turning On the Power
|
||||||
///
|
///
|
||||||
/// After the Power ON command, the driver will power on following the Power ON
|
/// After the Power ON command, the driver will power on following the Power ON
|
||||||
/// sequence. Once complete, the BUSY signal will become "1".
|
/// sequence. Once complete, the BUSY signal will become "1".
|
||||||
POWER_ON = 0x04,
|
PowerOn = 0x04,
|
||||||
|
|
||||||
/// Starting data transmission
|
/// Starting data transmission
|
||||||
BOOSTER_SOFT_START = 0x06,
|
BoosterSoftStart = 0x06,
|
||||||
|
|
||||||
/// This command makes the chip enter the deep-sleep mode to save power.
|
/// This command makes the chip enter the deep-sleep mode to save power.
|
||||||
///
|
///
|
||||||
/// The deep sleep mode would return to stand-by by hardware reset.
|
/// The deep sleep mode would return to stand-by by hardware reset.
|
||||||
///
|
///
|
||||||
/// The only one parameter is a check code, the command would be excuted if check code = 0xA5.
|
/// The only one parameter is a check code, the command would be excuted if check code = 0xA5.
|
||||||
DEEP_SLEEP = 0x07,
|
DeepSleep = 0x07,
|
||||||
|
|
||||||
/// This command starts transmitting data and write them into SRAM. To complete data
|
/// This command starts transmitting data and write them into SRAM. To complete data
|
||||||
/// transmission, command DSP (Data Stop) must be issued. Then the chip will start to
|
/// transmission, command DSP (Data Stop) must be issued. Then the chip will start to
|
||||||
/// send data/VCOM for panel.
|
/// send data/VCOM for panel.
|
||||||
DATA_START_TRANSMISSION_1 = 0x10,
|
DataStartTransmission1 = 0x10,
|
||||||
|
|
||||||
/// To stop data transmission, this command must be issued to check the `data_flag`.
|
/// To stop data transmission, this command must be issued to check the `data_flag`.
|
||||||
///
|
///
|
||||||
/// After this command, BUSY signal will become "0" until the display update is
|
/// After this command, BUSY signal will become "0" until the display update is
|
||||||
/// finished.
|
/// finished.
|
||||||
DATA_STOP = 0x11,
|
DataStop = 0x11,
|
||||||
|
|
||||||
/// After this command is issued, driver will refresh display (data/VCOM) according to
|
/// After this command is issued, driver will refresh display (data/VCOM) according to
|
||||||
/// SRAM data and LUT.
|
/// SRAM data and LUT.
|
||||||
///
|
///
|
||||||
/// After Display Refresh command, BUSY signal will become "0" until the display
|
/// After Display Refresh command, BUSY signal will become "0" until the display
|
||||||
/// update is finished.
|
/// update is finished.
|
||||||
DISPLAY_REFRESH = 0x12,
|
DisplayRefresh = 0x12,
|
||||||
|
|
||||||
/// After this command is issued, image process engine will find thin lines/pixels
|
/// After this command is issued, image process engine will find thin lines/pixels
|
||||||
/// from frame SRAM and update the frame SRAM for applying new gray level waveform.
|
/// from frame SRAM and update the frame SRAM for applying new gray level waveform.
|
||||||
///
|
///
|
||||||
/// After "Image Process Command", BUSY_N signal will become "0" until image process
|
/// After "Image Process Command", BUSY_N signal will become "0" until image process
|
||||||
/// is finished.
|
/// is finished.
|
||||||
IMAGE_PROCESS = 0x13,
|
ImageProcess = 0x13,
|
||||||
|
|
||||||
/// This command builds the VCOM Look-Up Table (LUTC).
|
/// This command builds the VCOM Look-Up Table (LUTC).
|
||||||
LUT_FOR_VCOM = 0x20,
|
LutForVcom = 0x20,
|
||||||
/// This command builds the Black Look-Up Table (LUTB).
|
/// This command builds the Black Look-Up Table (LUTB).
|
||||||
LUT_BLACK = 0x21,
|
LutBlack = 0x21,
|
||||||
/// This command builds the White Look-Up Table (LUTW).
|
/// This command builds the White Look-Up Table (LUTW).
|
||||||
LUT_WHITE = 0x22,
|
LutWhite = 0x22,
|
||||||
/// This command builds the Gray1 Look-Up Table (LUTG1).
|
/// This command builds the Gray1 Look-Up Table (LUTG1).
|
||||||
LUT_GRAY_1 = 0x23,
|
LutGray1 = 0x23,
|
||||||
/// This command builds the Gray2 Look-Up Table (LUTG2).
|
/// This command builds the Gray2 Look-Up Table (LUTG2).
|
||||||
LUT_GRAY_2 = 0x24,
|
LutGray2 = 0x24,
|
||||||
/// This command builds the Red0 Look-Up Table (LUTR0).
|
/// This command builds the Red0 Look-Up Table (LUTR0).
|
||||||
LUT_RED_0 = 0x25,
|
LutRed0 = 0x25,
|
||||||
/// This command builds the Red1 Look-Up Table (LUTR1).
|
/// This command builds the Red1 Look-Up Table (LUTR1).
|
||||||
LUT_RED_1 = 0x26,
|
LutRed1 = 0x26,
|
||||||
/// This command builds the Red2 Look-Up Table (LUTR2).
|
/// This command builds the Red2 Look-Up Table (LUTR2).
|
||||||
LUT_RED_2 = 0x27,
|
LutRed2 = 0x27,
|
||||||
/// This command builds the Red3 Look-Up Table (LUTR3).
|
/// This command builds the Red3 Look-Up Table (LUTR3).
|
||||||
LUT_RED_3 = 0x28,
|
LutRed3 = 0x28,
|
||||||
/// This command builds the XON Look-Up Table (LUTXON).
|
/// This command builds the XON Look-Up Table (LUTXON).
|
||||||
LUT_XON = 0x29,
|
LutXon = 0x29,
|
||||||
|
|
||||||
/// The command controls the PLL clock frequency.
|
/// The command controls the PLL clock frequency.
|
||||||
PLL_CONTROL = 0x30,
|
PllControl = 0x30,
|
||||||
|
|
||||||
/// This command reads the temperature sensed by the temperature sensor.
|
/// This command reads the temperature sensed by the temperature sensor.
|
||||||
TEMPERATURE_SENSOR_COMMAND = 0x40,
|
TemperatureSensor = 0x40,
|
||||||
/// This command selects the Internal or External temperature sensor.
|
/// This command selects the Internal or External temperature sensor.
|
||||||
TEMPERATURE_CALIBRATION = 0x41,
|
TemperatureCalibration = 0x41,
|
||||||
/// This command could write data to the external temperature sensor.
|
/// This command could write data to the external temperature sensor.
|
||||||
TEMPERATURE_SENSOR_WRITE = 0x42,
|
TemperatureSensorWrite = 0x42,
|
||||||
/// This command could read data from the external temperature sensor.
|
/// This command could read data from the external temperature sensor.
|
||||||
TEMPERATURE_SENSOR_READ = 0x43,
|
TemperatureSensorRead = 0x43,
|
||||||
|
|
||||||
/// This command indicates the interval of Vcom and data output. When setting the
|
/// This command indicates the interval of Vcom and data output. When setting the
|
||||||
/// vertical back porch, the total blanking will be kept (20 Hsync).
|
/// vertical back porch, the total blanking will be kept (20 Hsync).
|
||||||
VCOM_AND_DATA_INTERVAL_SETTING = 0x50,
|
VcomAndDataIntervalSetting = 0x50,
|
||||||
/// This command indicates the input power condition. Host can read this flag to learn
|
/// This command indicates the input power condition. Host can read this flag to learn
|
||||||
/// the battery condition.
|
/// the battery condition.
|
||||||
LOW_POWER_DETECTION = 0x51,
|
LowPowerDetection = 0x51,
|
||||||
|
|
||||||
/// This command defines non-overlap period of Gate and Source.
|
/// This command defines non-overlap period of Gate and Source.
|
||||||
TCON_SETTING = 0x60,
|
TconSetting = 0x60,
|
||||||
/// This command defines alternative resolution and this setting is of higher priority
|
/// This command defines alternative resolution and this setting is of higher priority
|
||||||
/// than the RES\[1:0\] in R00H (PSR).
|
/// than the RES\[1:0\] in R00H (PSR).
|
||||||
TCON_RESOLUTION = 0x61,
|
TconResolution = 0x61,
|
||||||
/// This command defines MCU host direct access external memory mode.
|
/// This command defines MCU host direct access external memory mode.
|
||||||
SPI_FLASH_CONTROL = 0x65,
|
SpiFlashControl = 0x65,
|
||||||
|
|
||||||
/// The LUT_REV / Chip Revision is read from OTP address = 25001 and 25000.
|
/// The LUT_REV / Chip Revision is read from OTP address = 25001 and 25000.
|
||||||
REVISION = 0x70,
|
Revision = 0x70,
|
||||||
/// This command reads the IC status.
|
/// This command reads the IC status.
|
||||||
GET_STATUS = 0x71,
|
GetStatus = 0x71,
|
||||||
|
|
||||||
/// This command implements related VCOM sensing setting.
|
/// This command implements related VCOM sensing setting.
|
||||||
AUTO_MEASUREMENT_VCOM = 0x80,
|
AutoMeasurementVcom = 0x80,
|
||||||
/// This command gets the VCOM value.
|
/// This command gets the VCOM value.
|
||||||
READ_VCOM_VALUE = 0x81,
|
ReadVcomValue = 0x81,
|
||||||
/// This command sets `VCOM_DC` value.
|
/// This command sets `VCOM_DC` value.
|
||||||
VCM_DC_SETTING = 0x82,
|
VcmDcSetting = 0x82,
|
||||||
|
|
||||||
/// This is in all the Waveshare controllers for EPD7in5, but it's not documented
|
/// This is in all the Waveshare controllers for Epd7in5, but it's not documented
|
||||||
/// anywhere in the datasheet `¯\_(ツ)_/¯`
|
/// anywhere in the datasheet `¯\_(ツ)_/¯`
|
||||||
FLASH_MODE = 0xE5,
|
FlashMode = 0xE5,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl traits::Command for Command {
|
impl traits::Command for Command {
|
||||||
|
|
@ -148,7 +147,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn command_addr() {
|
fn command_addr() {
|
||||||
assert_eq!(Command::PANEL_SETTING.address(), 0x00);
|
assert_eq!(Command::PanelSetting.address(), 0x00);
|
||||||
assert_eq!(Command::DISPLAY_REFRESH.address(), 0x12);
|
assert_eq!(Command::DisplayRefresh.address(), 0x12);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ use embedded_hal::{
|
||||||
|
|
||||||
use crate::color::Color;
|
use crate::color::Color;
|
||||||
use crate::interface::DisplayInterface;
|
use crate::interface::DisplayInterface;
|
||||||
use crate::traits::{InternalWiAdditions, RefreshLUT, WaveshareDisplay};
|
use crate::traits::{InternalWiAdditions, RefreshLut, WaveshareDisplay};
|
||||||
|
|
||||||
pub(crate) mod command;
|
pub(crate) mod command;
|
||||||
use self::command::Command;
|
use self::command::Command;
|
||||||
|
|
@ -31,9 +31,9 @@ pub const HEIGHT: u32 = 384;
|
||||||
pub const DEFAULT_BACKGROUND_COLOR: Color = Color::White;
|
pub const DEFAULT_BACKGROUND_COLOR: Color = Color::White;
|
||||||
const IS_BUSY_LOW: bool = true;
|
const IS_BUSY_LOW: bool = true;
|
||||||
|
|
||||||
/// EPD7in5 driver
|
/// Epd7in5 driver
|
||||||
///
|
///
|
||||||
pub struct EPD7in5<SPI, CS, BUSY, DC, RST> {
|
pub struct Epd7in5<SPI, CS, BUSY, DC, RST> {
|
||||||
/// Connection Interface
|
/// Connection Interface
|
||||||
interface: DisplayInterface<SPI, CS, BUSY, DC, RST>,
|
interface: DisplayInterface<SPI, CS, BUSY, DC, RST>,
|
||||||
/// Background Color
|
/// Background Color
|
||||||
|
|
@ -41,7 +41,7 @@ pub struct EPD7in5<SPI, CS, BUSY, DC, RST> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<SPI, CS, BUSY, DC, RST> InternalWiAdditions<SPI, CS, BUSY, DC, RST>
|
impl<SPI, CS, BUSY, DC, RST> InternalWiAdditions<SPI, CS, BUSY, DC, RST>
|
||||||
for EPD7in5<SPI, CS, BUSY, DC, RST>
|
for Epd7in5<SPI, CS, BUSY, DC, RST>
|
||||||
where
|
where
|
||||||
SPI: Write<u8>,
|
SPI: Write<u8>,
|
||||||
CS: OutputPin,
|
CS: OutputPin,
|
||||||
|
|
@ -58,41 +58,41 @@ where
|
||||||
self.interface.reset(delay, 10);
|
self.interface.reset(delay, 10);
|
||||||
|
|
||||||
// Set the power settings
|
// Set the power settings
|
||||||
self.cmd_with_data(spi, Command::POWER_SETTING, &[0x37, 0x00])?;
|
self.cmd_with_data(spi, Command::PowerSetting, &[0x37, 0x00])?;
|
||||||
|
|
||||||
// Set the panel settings:
|
// Set the panel settings:
|
||||||
// - 600 x 448
|
// - 600 x 448
|
||||||
// - Using LUT from external flash
|
// - Using LUT from external flash
|
||||||
self.cmd_with_data(spi, Command::PANEL_SETTING, &[0xCF, 0x08])?;
|
self.cmd_with_data(spi, Command::PanelSetting, &[0xCF, 0x08])?;
|
||||||
|
|
||||||
// Start the booster
|
// Start the booster
|
||||||
self.cmd_with_data(spi, Command::BOOSTER_SOFT_START, &[0xC7, 0xCC, 0x28])?;
|
self.cmd_with_data(spi, Command::BoosterSoftStart, &[0xC7, 0xCC, 0x28])?;
|
||||||
|
|
||||||
// Power on
|
// Power on
|
||||||
self.command(spi, Command::POWER_ON)?;
|
self.command(spi, Command::PowerOn)?;
|
||||||
delay.delay_ms(5);
|
delay.delay_ms(5);
|
||||||
self.wait_until_idle();
|
self.wait_until_idle();
|
||||||
|
|
||||||
// Set the clock frequency to 50Hz (default)
|
// Set the clock frequency to 50Hz (default)
|
||||||
self.cmd_with_data(spi, Command::PLL_CONTROL, &[0x3C])?;
|
self.cmd_with_data(spi, Command::PllControl, &[0x3C])?;
|
||||||
|
|
||||||
// Select internal temperature sensor (default)
|
// Select internal temperature sensor (default)
|
||||||
self.cmd_with_data(spi, Command::TEMPERATURE_CALIBRATION, &[0x00])?;
|
self.cmd_with_data(spi, Command::TemperatureCalibration, &[0x00])?;
|
||||||
|
|
||||||
// Set Vcom and data interval to 10 (default), border output to white
|
// Set Vcom and data interval to 10 (default), border output to white
|
||||||
self.cmd_with_data(spi, Command::VCOM_AND_DATA_INTERVAL_SETTING, &[0x77])?;
|
self.cmd_with_data(spi, Command::VcomAndDataIntervalSetting, &[0x77])?;
|
||||||
|
|
||||||
// Set S2G and G2S non-overlap periods to 12 (default)
|
// Set S2G and G2S non-overlap periods to 12 (default)
|
||||||
self.cmd_with_data(spi, Command::TCON_SETTING, &[0x22])?;
|
self.cmd_with_data(spi, Command::TconSetting, &[0x22])?;
|
||||||
|
|
||||||
// Set the real resolution
|
// Set the real resolution
|
||||||
self.send_resolution(spi)?;
|
self.send_resolution(spi)?;
|
||||||
|
|
||||||
// Set VCOM_DC to -1.5V
|
// Set VCOM_DC to -1.5V
|
||||||
self.cmd_with_data(spi, Command::VCM_DC_SETTING, &[0x1E])?;
|
self.cmd_with_data(spi, Command::VcmDcSetting, &[0x1E])?;
|
||||||
|
|
||||||
// This is in all the Waveshare controllers for EPD7in5
|
// This is in all the Waveshare controllers for Epd7in5
|
||||||
self.cmd_with_data(spi, Command::FLASH_MODE, &[0x03])?;
|
self.cmd_with_data(spi, Command::FlashMode, &[0x03])?;
|
||||||
|
|
||||||
self.wait_until_idle();
|
self.wait_until_idle();
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
@ -100,7 +100,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<SPI, CS, BUSY, DC, RST> WaveshareDisplay<SPI, CS, BUSY, DC, RST>
|
impl<SPI, CS, BUSY, DC, RST> WaveshareDisplay<SPI, CS, BUSY, DC, RST>
|
||||||
for EPD7in5<SPI, CS, BUSY, DC, RST>
|
for Epd7in5<SPI, CS, BUSY, DC, RST>
|
||||||
where
|
where
|
||||||
SPI: Write<u8>,
|
SPI: Write<u8>,
|
||||||
CS: OutputPin,
|
CS: OutputPin,
|
||||||
|
|
@ -120,7 +120,7 @@ where
|
||||||
let interface = DisplayInterface::new(cs, busy, dc, rst);
|
let interface = DisplayInterface::new(cs, busy, dc, rst);
|
||||||
let color = DEFAULT_BACKGROUND_COLOR;
|
let color = DEFAULT_BACKGROUND_COLOR;
|
||||||
|
|
||||||
let mut epd = EPD7in5 { interface, color };
|
let mut epd = Epd7in5 { interface, color };
|
||||||
|
|
||||||
epd.init(spi, delay)?;
|
epd.init(spi, delay)?;
|
||||||
|
|
||||||
|
|
@ -137,15 +137,15 @@ where
|
||||||
|
|
||||||
fn sleep(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> {
|
fn sleep(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> {
|
||||||
self.wait_until_idle();
|
self.wait_until_idle();
|
||||||
self.command(spi, Command::POWER_OFF)?;
|
self.command(spi, Command::PowerOff)?;
|
||||||
self.wait_until_idle();
|
self.wait_until_idle();
|
||||||
self.cmd_with_data(spi, Command::DEEP_SLEEP, &[0xA5])?;
|
self.cmd_with_data(spi, Command::DeepSleep, &[0xA5])?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_frame(&mut self, spi: &mut SPI, buffer: &[u8]) -> Result<(), SPI::Error> {
|
fn update_frame(&mut self, spi: &mut SPI, buffer: &[u8]) -> Result<(), SPI::Error> {
|
||||||
self.wait_until_idle();
|
self.wait_until_idle();
|
||||||
self.command(spi, Command::DATA_START_TRANSMISSION_1)?;
|
self.command(spi, Command::DataStartTransmission1)?;
|
||||||
for byte in buffer {
|
for byte in buffer {
|
||||||
let mut temp = *byte;
|
let mut temp = *byte;
|
||||||
for _ in 0..4 {
|
for _ in 0..4 {
|
||||||
|
|
@ -174,13 +174,13 @@ where
|
||||||
|
|
||||||
fn display_frame(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> {
|
fn display_frame(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> {
|
||||||
self.wait_until_idle();
|
self.wait_until_idle();
|
||||||
self.command(spi, Command::DISPLAY_REFRESH)?;
|
self.command(spi, Command::DisplayRefresh)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_and_display_frame(&mut self, spi: &mut SPI, buffer: &[u8]) -> Result<(), SPI::Error> {
|
fn update_and_display_frame(&mut self, spi: &mut SPI, buffer: &[u8]) -> Result<(), SPI::Error> {
|
||||||
self.update_frame(spi, buffer)?;
|
self.update_frame(spi, buffer)?;
|
||||||
self.command(spi, Command::DISPLAY_REFRESH)?;
|
self.command(spi, Command::DisplayRefresh)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -189,7 +189,7 @@ where
|
||||||
self.send_resolution(spi)?;
|
self.send_resolution(spi)?;
|
||||||
|
|
||||||
// The Waveshare controllers all implement clear using 0x33
|
// The Waveshare controllers all implement clear using 0x33
|
||||||
self.command(spi, Command::DATA_START_TRANSMISSION_1)?;
|
self.command(spi, Command::DataStartTransmission1)?;
|
||||||
self.interface
|
self.interface
|
||||||
.data_x_times(spi, 0x33, WIDTH / 8 * HEIGHT * 4)?;
|
.data_x_times(spi, 0x33, WIDTH / 8 * HEIGHT * 4)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
@ -214,7 +214,7 @@ where
|
||||||
fn set_lut(
|
fn set_lut(
|
||||||
&mut self,
|
&mut self,
|
||||||
_spi: &mut SPI,
|
_spi: &mut SPI,
|
||||||
_refresh_rate: Option<RefreshLUT>,
|
_refresh_rate: Option<RefreshLut>,
|
||||||
) -> Result<(), SPI::Error> {
|
) -> Result<(), SPI::Error> {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
@ -224,7 +224,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<SPI, CS, BUSY, DC, RST> EPD7in5<SPI, CS, BUSY, DC, RST>
|
impl<SPI, CS, BUSY, DC, RST> Epd7in5<SPI, CS, BUSY, DC, RST>
|
||||||
where
|
where
|
||||||
SPI: Write<u8>,
|
SPI: Write<u8>,
|
||||||
CS: OutputPin,
|
CS: OutputPin,
|
||||||
|
|
@ -257,7 +257,7 @@ where
|
||||||
let w = self.width();
|
let w = self.width();
|
||||||
let h = self.height();
|
let h = self.height();
|
||||||
|
|
||||||
self.command(spi, Command::TCON_RESOLUTION)?;
|
self.command(spi, Command::TconResolution)?;
|
||||||
self.send_data(spi, &[(w >> 8) as u8])?;
|
self.send_data(spi, &[(w >> 8) as u8])?;
|
||||||
self.send_data(spi, &[w as u8])?;
|
self.send_data(spi, &[w as u8])?;
|
||||||
self.send_data(spi, &[(h >> 8) as u8])?;
|
self.send_data(spi, &[(h >> 8) as u8])?;
|
||||||
|
|
|
||||||
|
|
@ -2,136 +2,135 @@
|
||||||
|
|
||||||
use crate::traits;
|
use crate::traits;
|
||||||
|
|
||||||
/// EPD7in5 commands
|
/// Epd7in5 commands
|
||||||
///
|
///
|
||||||
/// Should rarely (never?) be needed directly.
|
/// Should rarely (never?) be needed directly.
|
||||||
///
|
///
|
||||||
/// For more infos about the addresses and what they are doing look into the PDFs.
|
/// For more infos about the addresses and what they are doing look into the PDFs.
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[allow(non_camel_case_types)]
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
pub(crate) enum Command {
|
pub(crate) enum Command {
|
||||||
/// Set Resolution, LUT selection, BWR pixels, gate scan direction, source shift
|
/// Set Resolution, LUT selection, BWR pixels, gate scan direction, source shift
|
||||||
/// direction, booster switch, soft reset.
|
/// direction, booster switch, soft reset.
|
||||||
PANEL_SETTING = 0x00,
|
PanelSetting = 0x00,
|
||||||
|
|
||||||
/// Selecting internal and external power
|
/// Selecting internal and external power
|
||||||
POWER_SETTING = 0x01,
|
PowerSetting = 0x01,
|
||||||
|
|
||||||
/// After the Power Off command, the driver will power off following the Power Off
|
/// After the Power Off command, the driver will power off following the Power Off
|
||||||
/// Sequence; BUSY signal will become "0". This command will turn off charge pump,
|
/// Sequence; BUSY signal will become "0". This command will turn off charge pump,
|
||||||
/// T-con, source driver, gate driver, VCOM, and temperature sensor, but register
|
/// T-con, source driver, gate driver, VCOM, and temperature sensor, but register
|
||||||
/// data will be kept until VDD becomes OFF. Source Driver output and Vcom will remain
|
/// data will be kept until VDD becomes OFF. Source Driver output and Vcom will remain
|
||||||
/// as previous condition, which may have 2 conditions: 0V or floating.
|
/// as previous condition, which may have 2 conditions: 0V or floating.
|
||||||
POWER_OFF = 0x02,
|
PowerOff = 0x02,
|
||||||
|
|
||||||
/// Setting Power OFF sequence
|
/// Setting Power OFF sequence
|
||||||
POWER_OFF_SEQUENCE_SETTING = 0x03,
|
PowerOffSequenceSetting = 0x03,
|
||||||
|
|
||||||
/// Turning On the Power
|
/// Turning On the Power
|
||||||
///
|
///
|
||||||
/// After the Power ON command, the driver will power on following the Power ON
|
/// After the Power ON command, the driver will power on following the Power ON
|
||||||
/// sequence. Once complete, the BUSY signal will become "1".
|
/// sequence. Once complete, the BUSY signal will become "1".
|
||||||
POWER_ON = 0x04,
|
PowerOn = 0x04,
|
||||||
|
|
||||||
/// Starting data transmission
|
/// Starting data transmission
|
||||||
BOOSTER_SOFT_START = 0x06,
|
BoosterSoftStart = 0x06,
|
||||||
|
|
||||||
/// This command makes the chip enter the deep-sleep mode to save power.
|
/// This command makes the chip enter the deep-sleep mode to save power.
|
||||||
///
|
///
|
||||||
/// The deep sleep mode would return to stand-by by hardware reset.
|
/// The deep sleep mode would return to stand-by by hardware reset.
|
||||||
///
|
///
|
||||||
/// The only one parameter is a check code, the command would be excuted if check code = 0xA5.
|
/// The only one parameter is a check code, the command would be excuted if check code = 0xA5.
|
||||||
DEEP_SLEEP = 0x07,
|
DeepSleep = 0x07,
|
||||||
|
|
||||||
/// This command starts transmitting data and write them into SRAM. To complete data
|
/// This command starts transmitting data and write them into SRAM. To complete data
|
||||||
/// transmission, command DSP (Data Stop) must be issued. Then the chip will start to
|
/// transmission, command DSP (Data Stop) must be issued. Then the chip will start to
|
||||||
/// send data/VCOM for panel.
|
/// send data/VCOM for panel.
|
||||||
///
|
///
|
||||||
/// BLACK/WHITE or OLD_DATA
|
/// BLACK/WHITE or OLD_DATA
|
||||||
DATA_START_TRANSMISSION_1 = 0x10,
|
DataStartTransmission1 = 0x10,
|
||||||
|
|
||||||
/// To stop data transmission, this command must be issued to check the `data_flag`.
|
/// To stop data transmission, this command must be issued to check the `data_flag`.
|
||||||
///
|
///
|
||||||
/// After this command, BUSY signal will become "0" until the display update is
|
/// After this command, BUSY signal will become "0" until the display update is
|
||||||
/// finished.
|
/// finished.
|
||||||
DATA_STOP = 0x11,
|
DataStop = 0x11,
|
||||||
|
|
||||||
/// After this command is issued, driver will refresh display (data/VCOM) according to
|
/// After this command is issued, driver will refresh display (data/VCOM) according to
|
||||||
/// SRAM data and LUT.
|
/// SRAM data and LUT.
|
||||||
///
|
///
|
||||||
/// After Display Refresh command, BUSY signal will become "0" until the display
|
/// After Display Refresh command, BUSY signal will become "0" until the display
|
||||||
/// update is finished.
|
/// update is finished.
|
||||||
DISPLAY_REFRESH = 0x12,
|
DisplayRefresh = 0x12,
|
||||||
|
|
||||||
/// RED or NEW_DATA
|
/// RED or NEW_DATA
|
||||||
DATA_START_TRANSMISSION_2 = 0x13,
|
DataStartTransmission2 = 0x13,
|
||||||
|
|
||||||
/// Dual SPI - what for?
|
/// Dual SPI - what for?
|
||||||
DUAL_SPI = 0x15,
|
DualSpi = 0x15,
|
||||||
|
|
||||||
/// This command builds the VCOM Look-Up Table (LUTC).
|
/// This command builds the VCOM Look-Up Table (LUTC).
|
||||||
LUT_FOR_VCOM = 0x20,
|
LutForVcom = 0x20,
|
||||||
/// This command builds the Black Look-Up Table (LUTB).
|
/// This command builds the Black Look-Up Table (LUTB).
|
||||||
LUT_BLACK = 0x21,
|
LutBlack = 0x21,
|
||||||
/// This command builds the White Look-Up Table (LUTW).
|
/// This command builds the White Look-Up Table (LUTW).
|
||||||
LUT_WHITE = 0x22,
|
LutWhite = 0x22,
|
||||||
/// This command builds the Gray1 Look-Up Table (LUTG1).
|
/// This command builds the Gray1 Look-Up Table (LUTG1).
|
||||||
LUT_GRAY_1 = 0x23,
|
LutGray1 = 0x23,
|
||||||
/// This command builds the Gray2 Look-Up Table (LUTG2).
|
/// This command builds the Gray2 Look-Up Table (LUTG2).
|
||||||
LUT_GRAY_2 = 0x24,
|
LutGray2 = 0x24,
|
||||||
/// This command builds the Red0 Look-Up Table (LUTR0).
|
/// This command builds the Red0 Look-Up Table (LUTR0).
|
||||||
LUT_RED_0 = 0x25,
|
LutRed0 = 0x25,
|
||||||
/// This command builds the Red1 Look-Up Table (LUTR1).
|
/// This command builds the Red1 Look-Up Table (LUTR1).
|
||||||
LUT_RED_1 = 0x26,
|
LutRed1 = 0x26,
|
||||||
/// This command builds the Red2 Look-Up Table (LUTR2).
|
/// This command builds the Red2 Look-Up Table (LUTR2).
|
||||||
LUT_RED_2 = 0x27,
|
LutRed2 = 0x27,
|
||||||
/// This command builds the Red3 Look-Up Table (LUTR3).
|
/// This command builds the Red3 Look-Up Table (LUTR3).
|
||||||
LUT_RED_3 = 0x28,
|
LutRed3 = 0x28,
|
||||||
/// This command builds the XON Look-Up Table (LUTXON).
|
/// This command builds the XON Look-Up Table (LUTXON).
|
||||||
LUT_XON = 0x29,
|
LutXon = 0x29,
|
||||||
|
|
||||||
/// The command controls the PLL clock frequency.
|
/// The command controls the PLL clock frequency.
|
||||||
PLL_CONTROL = 0x30,
|
PllControl = 0x30,
|
||||||
|
|
||||||
/// This command reads the temperature sensed by the temperature sensor.
|
/// This command reads the temperature sensed by the temperature sensor.
|
||||||
TEMPERATURE_SENSOR_COMMAND = 0x40,
|
TemperatureSensor = 0x40,
|
||||||
/// This command selects the Internal or External temperature sensor.
|
/// This command selects the Internal or External temperature sensor.
|
||||||
TEMPERATURE_CALIBRATION = 0x41,
|
TemperatureCalibration = 0x41,
|
||||||
/// This command could write data to the external temperature sensor.
|
/// This command could write data to the external temperature sensor.
|
||||||
TEMPERATURE_SENSOR_WRITE = 0x42,
|
TemperatureSensorWrite = 0x42,
|
||||||
/// This command could read data from the external temperature sensor.
|
/// This command could read data from the external temperature sensor.
|
||||||
TEMPERATURE_SENSOR_READ = 0x43,
|
TemperatureSensorRead = 0x43,
|
||||||
|
|
||||||
/// This command indicates the interval of Vcom and data output. When setting the
|
/// This command indicates the interval of Vcom and data output. When setting the
|
||||||
/// vertical back porch, the total blanking will be kept (20 Hsync).
|
/// vertical back porch, the total blanking will be kept (20 Hsync).
|
||||||
VCOM_AND_DATA_INTERVAL_SETTING = 0x50,
|
VcomAndDataIntervalSetting = 0x50,
|
||||||
/// This command indicates the input power condition. Host can read this flag to learn
|
/// This command indicates the input power condition. Host can read this flag to learn
|
||||||
/// the battery condition.
|
/// the battery condition.
|
||||||
LOW_POWER_DETECTION = 0x51,
|
LowPowerDetection = 0x51,
|
||||||
|
|
||||||
/// This command defines non-overlap period of Gate and Source.
|
/// This command defines non-overlap period of Gate and Source.
|
||||||
TCON_SETTING = 0x60,
|
TconSetting = 0x60,
|
||||||
/// This command defines alternative resolution and this setting is of higher priority
|
/// This command defines alternative resolution and this setting is of higher priority
|
||||||
/// than the RES\[1:0\] in R00H (PSR).
|
/// than the RES\[1:0\] in R00H (PSR).
|
||||||
TCON_RESOLUTION = 0x61,
|
TconResolution = 0x61,
|
||||||
/// This command defines MCU host direct access external memory mode.
|
/// This command defines MCU host direct access external memory mode.
|
||||||
SPI_FLASH_CONTROL = 0x65,
|
SpiFlashControl = 0x65,
|
||||||
|
|
||||||
/// The LUT_REV / Chip Revision is read from OTP address = 25001 and 25000.
|
/// The LUT_REV / Chip Revision is read from OTP address = 25001 and 25000.
|
||||||
REVISION = 0x70,
|
Revision = 0x70,
|
||||||
/// This command reads the IC status.
|
/// This command reads the IC status.
|
||||||
GET_STATUS = 0x71,
|
GetStatus = 0x71,
|
||||||
|
|
||||||
/// This command implements related VCOM sensing setting.
|
/// This command implements related VCOM sensing setting.
|
||||||
AUTO_MEASUREMENT_VCOM = 0x80,
|
AutoMeasurementVcom = 0x80,
|
||||||
/// This command gets the VCOM value.
|
/// This command gets the VCOM value.
|
||||||
READ_VCOM_VALUE = 0x81,
|
ReadVcomValue = 0x81,
|
||||||
/// This command sets `VCOM_DC` value.
|
/// This command sets `VCOM_DC` value.
|
||||||
VCM_DC_SETTING = 0x82,
|
VcmDcSetting = 0x82,
|
||||||
// /// This is in all the Waveshare controllers for EPD7in5, but it's not documented
|
// /// This is in all the Waveshare controllers for Epd7in5, but it's not documented
|
||||||
// /// anywhere in the datasheet `¯\_(ツ)_/¯`
|
// /// anywhere in the datasheet `¯\_(ツ)_/¯`
|
||||||
// FLASH_MODE = 0xE5,
|
// FlashMode = 0xE5,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl traits::Command for Command {
|
impl traits::Command for Command {
|
||||||
|
|
@ -148,7 +147,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn command_addr() {
|
fn command_addr() {
|
||||||
assert_eq!(Command::PANEL_SETTING.address(), 0x00);
|
assert_eq!(Command::PanelSetting.address(), 0x00);
|
||||||
assert_eq!(Command::DISPLAY_REFRESH.address(), 0x12);
|
assert_eq!(Command::DisplayRefresh.address(), 0x12);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ use embedded_hal::{
|
||||||
|
|
||||||
use crate::color::Color;
|
use crate::color::Color;
|
||||||
use crate::interface::DisplayInterface;
|
use crate::interface::DisplayInterface;
|
||||||
use crate::traits::{InternalWiAdditions, RefreshLUT, WaveshareDisplay};
|
use crate::traits::{InternalWiAdditions, RefreshLut, WaveshareDisplay};
|
||||||
|
|
||||||
pub(crate) mod command;
|
pub(crate) mod command;
|
||||||
use self::command::Command;
|
use self::command::Command;
|
||||||
|
|
@ -35,9 +35,9 @@ pub const HEIGHT: u32 = 480;
|
||||||
pub const DEFAULT_BACKGROUND_COLOR: Color = Color::White;
|
pub const DEFAULT_BACKGROUND_COLOR: Color = Color::White;
|
||||||
const IS_BUSY_LOW: bool = true;
|
const IS_BUSY_LOW: bool = true;
|
||||||
|
|
||||||
/// EPD7in5 (V2) driver
|
/// Epd7in5 (V2) driver
|
||||||
///
|
///
|
||||||
pub struct EPD7in5<SPI, CS, BUSY, DC, RST> {
|
pub struct Epd7in5<SPI, CS, BUSY, DC, RST> {
|
||||||
/// Connection Interface
|
/// Connection Interface
|
||||||
interface: DisplayInterface<SPI, CS, BUSY, DC, RST>,
|
interface: DisplayInterface<SPI, CS, BUSY, DC, RST>,
|
||||||
/// Background Color
|
/// Background Color
|
||||||
|
|
@ -45,7 +45,7 @@ pub struct EPD7in5<SPI, CS, BUSY, DC, RST> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<SPI, CS, BUSY, DC, RST> InternalWiAdditions<SPI, CS, BUSY, DC, RST>
|
impl<SPI, CS, BUSY, DC, RST> InternalWiAdditions<SPI, CS, BUSY, DC, RST>
|
||||||
for EPD7in5<SPI, CS, BUSY, DC, RST>
|
for Epd7in5<SPI, CS, BUSY, DC, RST>
|
||||||
where
|
where
|
||||||
SPI: Write<u8>,
|
SPI: Write<u8>,
|
||||||
CS: OutputPin,
|
CS: OutputPin,
|
||||||
|
|
@ -66,23 +66,23 @@ where
|
||||||
// and as per specs:
|
// and as per specs:
|
||||||
// https://www.waveshare.com/w/upload/6/60/7.5inch_e-Paper_V2_Specification.pdf
|
// https://www.waveshare.com/w/upload/6/60/7.5inch_e-Paper_V2_Specification.pdf
|
||||||
|
|
||||||
self.cmd_with_data(spi, Command::BOOSTER_SOFT_START, &[0x17, 0x17, 0x27, 0x17])?;
|
self.cmd_with_data(spi, Command::BoosterSoftStart, &[0x17, 0x17, 0x27, 0x17])?;
|
||||||
self.cmd_with_data(spi, Command::POWER_SETTING, &[0x07, 0x17, 0x3F, 0x3F])?;
|
self.cmd_with_data(spi, Command::PowerSetting, &[0x07, 0x17, 0x3F, 0x3F])?;
|
||||||
self.command(spi, Command::POWER_ON)?;
|
self.command(spi, Command::PowerOn)?;
|
||||||
self.wait_until_idle();
|
self.wait_until_idle();
|
||||||
self.cmd_with_data(spi, Command::PANEL_SETTING, &[0x1F])?;
|
self.cmd_with_data(spi, Command::PanelSetting, &[0x1F])?;
|
||||||
self.cmd_with_data(spi, Command::PLL_CONTROL, &[0x06])?;
|
self.cmd_with_data(spi, Command::PllControl, &[0x06])?;
|
||||||
self.cmd_with_data(spi, Command::TCON_RESOLUTION, &[0x03, 0x20, 0x01, 0xE0])?;
|
self.cmd_with_data(spi, Command::TconResolution, &[0x03, 0x20, 0x01, 0xE0])?;
|
||||||
self.cmd_with_data(spi, Command::DUAL_SPI, &[0x00])?;
|
self.cmd_with_data(spi, Command::DualSpi, &[0x00])?;
|
||||||
self.cmd_with_data(spi, Command::TCON_SETTING, &[0x22])?;
|
self.cmd_with_data(spi, Command::TconSetting, &[0x22])?;
|
||||||
self.cmd_with_data(spi, Command::VCOM_AND_DATA_INTERVAL_SETTING, &[0x10, 0x07])?;
|
self.cmd_with_data(spi, Command::VcomAndDataIntervalSetting, &[0x10, 0x07])?;
|
||||||
self.wait_until_idle();
|
self.wait_until_idle();
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<SPI, CS, BUSY, DC, RST> WaveshareDisplay<SPI, CS, BUSY, DC, RST>
|
impl<SPI, CS, BUSY, DC, RST> WaveshareDisplay<SPI, CS, BUSY, DC, RST>
|
||||||
for EPD7in5<SPI, CS, BUSY, DC, RST>
|
for Epd7in5<SPI, CS, BUSY, DC, RST>
|
||||||
where
|
where
|
||||||
SPI: Write<u8>,
|
SPI: Write<u8>,
|
||||||
CS: OutputPin,
|
CS: OutputPin,
|
||||||
|
|
@ -102,7 +102,7 @@ where
|
||||||
let interface = DisplayInterface::new(cs, busy, dc, rst);
|
let interface = DisplayInterface::new(cs, busy, dc, rst);
|
||||||
let color = DEFAULT_BACKGROUND_COLOR;
|
let color = DEFAULT_BACKGROUND_COLOR;
|
||||||
|
|
||||||
let mut epd = EPD7in5 { interface, color };
|
let mut epd = Epd7in5 { interface, color };
|
||||||
|
|
||||||
epd.init(spi, delay)?;
|
epd.init(spi, delay)?;
|
||||||
|
|
||||||
|
|
@ -119,15 +119,15 @@ where
|
||||||
|
|
||||||
fn sleep(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> {
|
fn sleep(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> {
|
||||||
self.wait_until_idle();
|
self.wait_until_idle();
|
||||||
self.command(spi, Command::POWER_OFF)?;
|
self.command(spi, Command::PowerOff)?;
|
||||||
self.wait_until_idle();
|
self.wait_until_idle();
|
||||||
self.cmd_with_data(spi, Command::DEEP_SLEEP, &[0xA5])?;
|
self.cmd_with_data(spi, Command::DeepSleep, &[0xA5])?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_frame(&mut self, spi: &mut SPI, buffer: &[u8]) -> Result<(), SPI::Error> {
|
fn update_frame(&mut self, spi: &mut SPI, buffer: &[u8]) -> Result<(), SPI::Error> {
|
||||||
self.wait_until_idle();
|
self.wait_until_idle();
|
||||||
self.cmd_with_data(spi, Command::DATA_START_TRANSMISSION_2, buffer)?;
|
self.cmd_with_data(spi, Command::DataStartTransmission2, buffer)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -145,13 +145,13 @@ where
|
||||||
|
|
||||||
fn display_frame(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> {
|
fn display_frame(&mut self, spi: &mut SPI) -> Result<(), SPI::Error> {
|
||||||
self.wait_until_idle();
|
self.wait_until_idle();
|
||||||
self.command(spi, Command::DISPLAY_REFRESH)?;
|
self.command(spi, Command::DisplayRefresh)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_and_display_frame(&mut self, spi: &mut SPI, buffer: &[u8]) -> Result<(), SPI::Error> {
|
fn update_and_display_frame(&mut self, spi: &mut SPI, buffer: &[u8]) -> Result<(), SPI::Error> {
|
||||||
self.update_frame(spi, buffer)?;
|
self.update_frame(spi, buffer)?;
|
||||||
self.command(spi, Command::DISPLAY_REFRESH)?;
|
self.command(spi, Command::DisplayRefresh)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -159,13 +159,13 @@ where
|
||||||
self.wait_until_idle();
|
self.wait_until_idle();
|
||||||
self.send_resolution(spi)?;
|
self.send_resolution(spi)?;
|
||||||
|
|
||||||
self.command(spi, Command::DATA_START_TRANSMISSION_1)?;
|
self.command(spi, Command::DataStartTransmission1)?;
|
||||||
self.interface.data_x_times(spi, 0x00, WIDTH * HEIGHT / 8)?;
|
self.interface.data_x_times(spi, 0x00, WIDTH * HEIGHT / 8)?;
|
||||||
|
|
||||||
self.command(spi, Command::DATA_START_TRANSMISSION_2)?;
|
self.command(spi, Command::DataStartTransmission2)?;
|
||||||
self.interface.data_x_times(spi, 0x00, WIDTH * HEIGHT / 8)?;
|
self.interface.data_x_times(spi, 0x00, WIDTH * HEIGHT / 8)?;
|
||||||
|
|
||||||
self.command(spi, Command::DISPLAY_REFRESH)?;
|
self.command(spi, Command::DisplayRefresh)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -188,7 +188,7 @@ where
|
||||||
fn set_lut(
|
fn set_lut(
|
||||||
&mut self,
|
&mut self,
|
||||||
_spi: &mut SPI,
|
_spi: &mut SPI,
|
||||||
_refresh_rate: Option<RefreshLUT>,
|
_refresh_rate: Option<RefreshLut>,
|
||||||
) -> Result<(), SPI::Error> {
|
) -> Result<(), SPI::Error> {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
@ -198,7 +198,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<SPI, CS, BUSY, DC, RST> EPD7in5<SPI, CS, BUSY, DC, RST>
|
impl<SPI, CS, BUSY, DC, RST> Epd7in5<SPI, CS, BUSY, DC, RST>
|
||||||
where
|
where
|
||||||
SPI: Write<u8>,
|
SPI: Write<u8>,
|
||||||
CS: OutputPin,
|
CS: OutputPin,
|
||||||
|
|
@ -231,7 +231,7 @@ where
|
||||||
let w = self.width();
|
let w = self.width();
|
||||||
let h = self.height();
|
let h = self.height();
|
||||||
|
|
||||||
self.command(spi, Command::TCON_RESOLUTION)?;
|
self.command(spi, Command::TconResolution)?;
|
||||||
self.send_data(spi, &[(w >> 8) as u8])?;
|
self.send_data(spi, &[(w >> 8) as u8])?;
|
||||||
self.send_data(spi, &[w as u8])?;
|
self.send_data(spi, &[w as u8])?;
|
||||||
self.send_data(spi, &[(h >> 8) as u8])?;
|
self.send_data(spi, &[(h >> 8) as u8])?;
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,7 @@ where
|
||||||
|
|
||||||
/// Basic function for sending an array of u8-values of data over spi
|
/// Basic function for sending an array of u8-values of data over spi
|
||||||
///
|
///
|
||||||
/// Enables direct interaction with the device with the help of [command()](EPD4in2::command())
|
/// Enables direct interaction with the device with the help of [command()](Epd4in2::command())
|
||||||
pub(crate) fn data(&mut self, spi: &mut SPI, data: &[u8]) -> Result<(), SPI::Error> {
|
pub(crate) fn data(&mut self, spi: &mut SPI, data: &[u8]) -> Result<(), SPI::Error> {
|
||||||
// high for data
|
// high for data
|
||||||
let _ = self.dc.set_high();
|
let _ = self.dc.set_high();
|
||||||
|
|
@ -157,7 +157,7 @@ where
|
||||||
|
|
||||||
/// Resets the device.
|
/// Resets the device.
|
||||||
///
|
///
|
||||||
/// Often used to awake the module from deep sleep. See [EPD4in2::sleep()](EPD4in2::sleep())
|
/// Often used to awake the module from deep sleep. See [Epd4in2::sleep()](Epd4in2::sleep())
|
||||||
///
|
///
|
||||||
/// The timing of keeping the reset pin low seems to be important and different per device.
|
/// The timing of keeping the reset pin low seems to be important and different per device.
|
||||||
/// Most displays seem to require keeping it low for 10ms, but the 7in5_v2 only seems to reset
|
/// Most displays seem to require keeping it low for 10ms, but the 7in5_v2 only seems to reset
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@
|
||||||
//!# let mut delay = delay::MockNoop::new();
|
//!# let mut delay = delay::MockNoop::new();
|
||||||
//!
|
//!
|
||||||
//!// Setup EPD
|
//!// Setup EPD
|
||||||
//!let mut epd = EPD1in54::new(&mut spi, cs_pin, busy_in, dc, rst, &mut delay)?;
|
//!let mut epd = Epd1in54::new(&mut spi, cs_pin, busy_in, dc, rst, &mut delay)?;
|
||||||
//!
|
//!
|
||||||
//!// Use display graphics from embedded-graphics
|
//!// Use display graphics from embedded-graphics
|
||||||
//!let mut display = Display1in54::default();
|
//!let mut display = Display1in54::default();
|
||||||
|
|
@ -91,7 +91,7 @@ pub(crate) mod type_a;
|
||||||
pub mod prelude {
|
pub mod prelude {
|
||||||
pub use crate::color::{Color, OctColor, TriColor};
|
pub use crate::color::{Color, OctColor, TriColor};
|
||||||
pub use crate::traits::{
|
pub use crate::traits::{
|
||||||
QuickRefresh, RefreshLUT, WaveshareDisplay, WaveshareThreeColorDisplay,
|
QuickRefresh, RefreshLut, WaveshareDisplay, WaveshareThreeColorDisplay,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub use crate::SPI_MODE;
|
pub use crate::SPI_MODE;
|
||||||
|
|
|
||||||
|
|
@ -12,17 +12,17 @@ pub(crate) trait Command {
|
||||||
|
|
||||||
/// Seperates the different LUT for the Display Refresh process
|
/// Seperates the different LUT for the Display Refresh process
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Copy)]
|
#[derive(Debug, Clone, PartialEq, Eq, Copy)]
|
||||||
pub enum RefreshLUT {
|
pub enum RefreshLut {
|
||||||
/// The "normal" full Lookuptable for the Refresh-Sequence
|
/// The "normal" full Lookuptable for the Refresh-Sequence
|
||||||
FULL,
|
Full,
|
||||||
/// The quick LUT where not the full refresh sequence is followed.
|
/// The quick LUT where not the full refresh sequence is followed.
|
||||||
/// This might lead to some
|
/// This might lead to some
|
||||||
QUICK,
|
Quick,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for RefreshLUT {
|
impl Default for RefreshLut {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
RefreshLUT::FULL
|
RefreshLut::Full
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -108,7 +108,7 @@ where
|
||||||
///# let mut delay = delay::MockNoop::new();
|
///# let mut delay = delay::MockNoop::new();
|
||||||
///
|
///
|
||||||
///// Setup EPD
|
///// Setup EPD
|
||||||
///let mut epd = EPD4in2::new(&mut spi, cs_pin, busy_in, dc, rst, &mut delay)?;
|
///let mut epd = Epd4in2::new(&mut spi, cs_pin, busy_in, dc, rst, &mut delay)?;
|
||||||
///
|
///
|
||||||
///// Use display graphics from embedded-graphics
|
///// Use display graphics from embedded-graphics
|
||||||
///let mut display = Display4in2::default();
|
///let mut display = Display4in2::default();
|
||||||
|
|
@ -219,7 +219,7 @@ where
|
||||||
fn set_lut(
|
fn set_lut(
|
||||||
&mut self,
|
&mut self,
|
||||||
spi: &mut SPI,
|
spi: &mut SPI,
|
||||||
refresh_rate: Option<RefreshLUT>,
|
refresh_rate: Option<RefreshLut>,
|
||||||
) -> Result<(), SPI::Error>;
|
) -> Result<(), SPI::Error>;
|
||||||
|
|
||||||
/// Checks if the display is busy transmitting data
|
/// Checks if the display is busy transmitting data
|
||||||
|
|
@ -258,7 +258,7 @@ where
|
||||||
///# let mut delay = delay::MockNoop::new();
|
///# let mut delay = delay::MockNoop::new();
|
||||||
///#
|
///#
|
||||||
///# // Setup EPD
|
///# // Setup EPD
|
||||||
///# let mut epd = EPD4in2::new(&mut spi, cs_pin, busy_in, dc, rst, &mut delay)?;
|
///# let mut epd = Epd4in2::new(&mut spi, cs_pin, busy_in, dc, rst, &mut delay)?;
|
||||||
///let (x, y, frame_width, frame_height) = (20, 40, 80,80);
|
///let (x, y, frame_width, frame_height) = (20, 40, 80,80);
|
||||||
///
|
///
|
||||||
///let mut buffer = [DEFAULT_BACKGROUND_COLOR.get_byte_value(); 80 / 8 * 80];
|
///let mut buffer = [DEFAULT_BACKGROUND_COLOR.get_byte_value(); 80 / 8 * 80];
|
||||||
|
|
|
||||||
|
|
@ -2,13 +2,12 @@
|
||||||
|
|
||||||
use crate::traits;
|
use crate::traits;
|
||||||
|
|
||||||
/// EPD1in54 and EPD2IN9 commands
|
/// Epd1in54 and EPD2IN9 commands
|
||||||
///
|
///
|
||||||
/// Should rarely (never?) be needed directly.
|
/// Should rarely (never?) be needed directly.
|
||||||
///
|
///
|
||||||
/// For more infos about the addresses and what they are doing look into the pdfs
|
/// For more infos about the addresses and what they are doing look into the pdfs
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[allow(non_camel_case_types)]
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
pub(crate) enum Command {
|
pub(crate) enum Command {
|
||||||
/// Driver Output control
|
/// Driver Output control
|
||||||
|
|
@ -17,58 +16,58 @@ pub(crate) enum Command {
|
||||||
/// 0.. A[8]
|
/// 0.. A[8]
|
||||||
/// 0.. B[2:0]
|
/// 0.. B[2:0]
|
||||||
/// Default: Set A[8:0] = 0x127 and B[2:0] = 0x0
|
/// Default: Set A[8:0] = 0x127 and B[2:0] = 0x0
|
||||||
DRIVER_OUTPUT_CONTROL = 0x01,
|
DriverOutputControl = 0x01,
|
||||||
/// Booster Soft start control
|
/// Booster Soft start control
|
||||||
/// 3 Databytes:
|
/// 3 Databytes:
|
||||||
/// 1.. A[6:0]
|
/// 1.. A[6:0]
|
||||||
/// 1.. B[6:0]
|
/// 1.. B[6:0]
|
||||||
/// 1.. C[6:0]
|
/// 1.. C[6:0]
|
||||||
/// Default: A[7:0] = 0xCF, B[7:0] = 0xCE, C[7:0] = 0x8D
|
/// Default: A[7:0] = 0xCF, B[7:0] = 0xCE, C[7:0] = 0x8D
|
||||||
BOOSTER_SOFT_START_CONTROL = 0x0C,
|
BoosterSoftStartControl = 0x0C,
|
||||||
GATE_SCAN_START_POSITION = 0x0F,
|
GateScanStartPosition = 0x0F,
|
||||||
//TODO: useful?
|
//TODO: useful?
|
||||||
// GATE_SCAN_START_POSITION = 0x0F,
|
// GateScanStartPosition = 0x0F,
|
||||||
/// Deep Sleep Mode Control
|
/// Deep Sleep Mode Control
|
||||||
/// 1 Databyte:
|
/// 1 Databyte:
|
||||||
/// 0.. A[0]
|
/// 0.. A[0]
|
||||||
/// Values:
|
/// Values:
|
||||||
/// A[0] = 0: Normal Mode (POR)
|
/// A[0] = 0: Normal Mode (POR)
|
||||||
/// A[0] = 1: Enter Deep Sleep Mode
|
/// A[0] = 1: Enter Deep Sleep Mode
|
||||||
DEEP_SLEEP_MODE = 0x10,
|
DeepSleepMode = 0x10,
|
||||||
// /// Data Entry mode setting
|
// /// Data Entry mode setting
|
||||||
DATA_ENTRY_MODE_SETTING = 0x11,
|
DataEntryModeSetting = 0x11,
|
||||||
|
|
||||||
SW_RESET = 0x12,
|
SwReset = 0x12,
|
||||||
|
|
||||||
TEMPERATURE_SENSOR_CONTROL = 0x1A,
|
TemperatureSensorControl = 0x1A,
|
||||||
|
|
||||||
MASTER_ACTIVATION = 0x20,
|
MasterActivation = 0x20,
|
||||||
|
|
||||||
DISPLAY_UPDATE_CONTROL_1 = 0x21,
|
DisplayUpdateControl1 = 0x21,
|
||||||
|
|
||||||
DISPLAY_UPDATE_CONTROL_2 = 0x22,
|
DisplayUpdateControl2 = 0x22,
|
||||||
|
|
||||||
WRITE_RAM = 0x24,
|
WriteRam = 0x24,
|
||||||
|
|
||||||
WRITE_VCOM_REGISTER = 0x2C,
|
WriteVcomRegister = 0x2C,
|
||||||
|
|
||||||
WRITE_LUT_REGISTER = 0x32,
|
WriteLutRegister = 0x32,
|
||||||
|
|
||||||
SET_DUMMY_LINE_PERIOD = 0x3A,
|
SetDummyLinePeriod = 0x3A,
|
||||||
|
|
||||||
SET_GATE_LINE_WIDTH = 0x3B,
|
SetGateLineWidth = 0x3B,
|
||||||
|
|
||||||
BORDER_WAVEFORM_CONTROL = 0x3C,
|
BorderWaveformControl = 0x3C,
|
||||||
|
|
||||||
SET_RAM_X_ADDRESS_START_END_POSITION = 0x44,
|
SetRamXAddressStartEndPosition = 0x44,
|
||||||
|
|
||||||
SET_RAM_Y_ADDRESS_START_END_POSITION = 0x45,
|
SetRamYAddressStartEndPosition = 0x45,
|
||||||
|
|
||||||
SET_RAM_X_ADDRESS_COUNTER = 0x4E,
|
SetRamXAddressCounter = 0x4E,
|
||||||
|
|
||||||
SET_RAM_Y_ADDRESS_COUNTER = 0x4F,
|
SetRamYAddressCounter = 0x4F,
|
||||||
|
|
||||||
NOP = 0xFF,
|
Nop = 0xFF,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl traits::Command for Command {
|
impl traits::Command for Command {
|
||||||
|
|
@ -85,10 +84,10 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn command_addr() {
|
fn command_addr() {
|
||||||
assert_eq!(Command::DRIVER_OUTPUT_CONTROL.address(), 0x01);
|
assert_eq!(Command::DriverOutputControl.address(), 0x01);
|
||||||
|
|
||||||
assert_eq!(Command::SET_RAM_X_ADDRESS_COUNTER.address(), 0x4E);
|
assert_eq!(Command::SetRamXAddressCounter.address(), 0x4E);
|
||||||
|
|
||||||
assert_eq!(Command::NOP.address(), 0xFF);
|
assert_eq!(Command::Nop.address(), 0xFF);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue