Browse Source

Merge pull request #40 from caemor/nidus

Improvements for 0.4
v0.4
Chris 3 years ago committed by GitHub
parent
commit
3871c1672e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 37
      .github/workflows/rust.yml
  2. 92
      .travis.yml
  3. 16
      CHANGELOG.md
  4. 31
      Cargo.toml
  5. 8
      README.md
  6. 47
      examples/Readme.md
  7. 13
      examples/epd1in54_full/Cargo.toml
  8. 150
      examples/epd1in54_full/src/main.rs
  9. 10
      examples/epd1in54_no_graphics.rs
  10. 12
      examples/epd1in54_no_graphics/Cargo.toml
  11. 13
      examples/epd2in9_full/Cargo.toml
  12. 154
      examples/epd2in9_full/src/main.rs
  13. 150
      examples/epd4in2.rs
  14. 15
      examples/epd4in2_full/Cargo.toml
  15. 189
      examples/epd4in2_full/src/main.rs
  16. 12
      examples/epd4in2_full_blue_pill/.cargo/config
  17. 19
      examples/epd4in2_full_blue_pill/Cargo.toml
  18. 6
      examples/epd4in2_full_blue_pill/memory.x
  19. 2
      examples/epd4in2_full_blue_pill/openocd.cfg
  20. 10
      examples/epd4in2_full_blue_pill/openocd.gdb
  21. 192
      examples/epd4in2_full_blue_pill/src/main.rs
  22. 15
      examples/epd4in2_var_display_buffer/Cargo.toml
  23. 139
      examples/epd4in2_variable_size.rs
  24. 14
      examples/epd7in5_full/Cargo.toml
  25. 188
      examples/epd7in5_full/src/main.rs
  26. 15
      examples/epd7in5_v2_full/Cargo.toml
  27. 188
      examples/epd7in5_v2_full/src/main.rs
  28. 13
      src/color.rs
  29. 54
      src/epd1in54/graphics.rs
  30. 90
      src/epd1in54/mod.rs
  31. 20
      src/epd1in54b/graphics.rs
  32. 22
      src/epd1in54b/mod.rs
  33. 17
      src/epd2in9/graphics.rs
  34. 90
      src/epd2in9/mod.rs
  35. 54
      src/epd4in2/graphics.rs
  36. 101
      src/epd4in2/mod.rs
  37. 53
      src/epd7in5/graphics.rs
  38. 37
      src/epd7in5/mod.rs
  39. 58
      src/epd7in5_v2/graphics.rs
  40. 57
      src/epd7in5_v2/mod.rs
  41. 110
      src/graphics.rs
  42. 106
      src/lib.rs
  43. 72
      src/traits.rs
  44. 30
      src/type_a/command.rs

37
.github/workflows/rust.yml

@ -0,0 +1,37 @@
name: Rust
on:
push:
branches:
- master
pull_request:
branches:
- master
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
rust:
- stable
- beta
steps:
- uses: actions/checkout@v1
- name: Install ARM toolchain
run: rustup target add thumbv7em-none-eabihf
- name: Check Fmt
run: cargo fmt --all -- --check
- name: Build lib
run: cargo check --all-targets --verbose
- name: Clippy
run: cargo clippy --all-targets --all-features -- -D warnings -A clippy::new_ret_no_self
- name: Build examples
run: cargo build --examples --all-targets --verbose
- name: Run tests
run: cargo test --verbose
- name: Build docs
run: cargo doc --all-features

92
.travis.yml

@ -1,98 +1,22 @@
# Based on the "trust" template v0.1.2
# https://github.com/japaric/trust/tree/v0.1.2
language: rust
rust:
- stable
- beta
- nightly
sudo: required
env: TARGET=x86_64-unknown-linux-gnu
# TODO Rust builds on stable by default, this can be
# overridden on a case by case basis down below.
matrix:
allow_failures:
- rust: nightly
- name: clippy
fast_finish: true
# TODO These are all the build jobs. Adjust as necessary. Comment out what you
# don't need
include:
# Linux
#- env: TARGET=aarch64-unknown-linux-gnu
# Raspberry Pi
- env: TARGET=arm-unknown-linux-gnueabi
# Raspberry Pi 3...
- env: TARGET=armv7-unknown-linux-gnueabihf
# is already included as global env
#- env: TARGET=x86_64-unknown-linux-gnu
- env: TARGET=x86_64-unknown-linux-musl
# Bare metal
# These targets don't support std and as such are likely not suitable for
# most crates.
- env: TARGET=thumbv6m-none-eabi
before_script: rustup target add $TARGET
script: cargo check --verbose --target $TARGET
- env: TARGET=thumbv7em-none-eabi
before_script: rustup target add $TARGET
script: cargo check --verbose --target $TARGET
- env: TARGET=thumbv7em-none-eabihf
before_script: rustup target add $TARGET
script: cargo check --verbose --target $TARGET
- env: TARGET=thumbv7m-none-eabi
before_script: rustup target add $TARGET
script: cargo check --verbose --target $TARGET
- name: "fmt"
rust: stable
env: RUN=FMT
before_script:
- rustup component add rustfmt
script:
- cargo fmt --all -- --check
- cargo doc --all-features --release
- cd examples/epd4in2_full && cargo fmt --all -- --check && cd ../../
- cd examples/epd2in9_full && cargo fmt --all -- --check && cd ../../
- cd examples/epd1in54_full && cargo fmt --all -- --check && cd ../../
- cd examples/epd1in54_no_graphics && cargo fmt --all -- --check && cd ../../
- cd examples/epd4in2_var_display_buffer && cargo fmt --all -- --check && cd ../../
- cd examples/epd4in2_full_blue_pill && cargo fmt --all -- --check && cd ../../
- name: "clippy"
rust: stable
env: RUN=FMT
before_script:
- rustup component add clippy
script:
- cargo clippy --all-targets --all-features -- -D warnings -A clippy::new_ret_no_self
- name: "check examples"
rust: stable
before_script:
- rustup target add thumbv7m-none-eabi
script:
- cd examples/epd4in2_full_blue_pill && cargo check && cd ../../
- cd examples/epd4in2_full && cargo check && cd ../../
- cd examples/epd2in9_full && cargo check && cd ../../
- cd examples/epd1in54_full && cargo check && cd ../../
- cd examples/epd1in54_no_graphics && cargo check && cd ../../
- cd examples/epd4in2_var_display_buffer && cargo check && cd ../../
- name
before_install:
- set -e
- rustup self update
install:
- cargo install cargo-update || echo "cargo-update already installed"
- cargo install-update -a # update outdated cached binaries
- cargo install cross || echo "cross already installed"
# install:
# - cargo install cargo-update || echo "cargo-update already installed"
# - cargo install-update -a # update outdated cached binaries
# - cargo install cross || echo "cross already installed"
#TODO: remove -A clippy::new_ret_no_self when new version of clippy gets released!
script:
- cross check --verbose --target $TARGET
- cross test --all-features --release --verbose --target $TARGET
- cargo check --all-features
- cargo test --all-features
cache: cargo
before_cache:
@ -100,7 +24,7 @@ before_cache:
- chmod -R a+r $HOME/.cargo
- |
if [[ "$TRAVIS_RUST_VERSION" == stable ]]; then
cargo install cargo-tarpaulin -f
cargo install cargo-tarpaulin
fi
after_success: |
@ -109,7 +33,7 @@ after_success: |
# cargo tarpaulin --ciserver travis-ci --coveralls $TRAVIS_JOB_ID
# Uncomment the following two lines create and upload a report for codecov.io
cargo tarpaulin --out Xml
cargo tarpaulin --all-features --out Xml
bash <(curl -s https://codecov.io/bash) -t "$CODECOV_TOKEN"
fi

16
CHANGELOG.md

@ -7,6 +7,22 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
## [Unreleased]
### Added
- 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)
- also improve position of busy_wait (#30) once more
- More Documenation
### Changed
- Update embedded-graphics to 0.6 (changes Display Trait) (and to 0.5 before thanks to @dbr)
- Remove useless Featuregates (Doesn't change size)
- Update and integrate a few important examples and remove the others
- Use Embedded_hal:digital::v2
### Fixed
- Doc Tests
<!-- ## [v0.3.2] - 2019-04-04 -->
## [v0.3.2] - 2019-06-17

31
Cargo.toml

@ -13,27 +13,20 @@ version = "0.3.2"
edition = "2018"
[badges]
# Travis CI: `repository` in format "<user>/<project>" is required.
# `branch` is optional; default is `master`
travis-ci = { repository = "caemor/epd-waveshare" }
# travis-ci = { repository = "caemor/epd-waveshare" }
[dependencies]
embedded-graphics = { version = "0.6.0", optional = true}
embedded-hal = {version = "0.2.3", features = ["unproven"]}
[dev-dependencies]
linux-embedded-hal = "0.3"
embedded-hal-mock = "0.7"
[features]
default = ["epd1in54", "epd1in54b", "epd2in9", "epd4in2", "epd7in5", "epd7in5_v2", "graphics"]
default = ["graphics"]
graphics = ["embedded-graphics"]
epd1in54 = []
epd1in54b = []
epd2in9 = []
epd4in2 = []
epd7in5 = []
epd7in5_v2 = []
# offers an alternative fast full lut for type_a displays, but the refresh isnt as clean looking
type_a_alternative_faster_lut = []
[dependencies.embedded-graphics]
optional = true
version = "0.5.2"
[dependencies.embedded-hal]
features = ["unproven"]
version = "0.2.3"
# Offers an alternative fast full lut for type_a displays, but the refreshed screen isnt as clean looking
type_a_alternative_faster_lut = []

8
README.md

@ -25,7 +25,7 @@ display.draw(
Font12x16::render_str("Hello Rust!")
.stroke(Some(Color::Black))
.fill(Some(Color::White))
.translate(Coord::new(5, 50))
.translate(Point::new(5, 50))
.into_iter(),
);
@ -45,7 +45,7 @@ epd.display_frame(&mut spi)?;
| [4.2 Inch B/W (A)](https://www.waveshare.com/product/4.2inch-e-paper-module.htm) | Black, White | ✕ | Not officially [[2](#2-42-inch-e-ink-blackwhite---partial-refresh)] | ✔ | ✔ |
| [1.54 Inch B/W (A)](https://www.waveshare.com/1.54inch-e-Paper-Module.htm) | Black, White | ✕ | ✔ | ✔ | ✔ |
| [2.13 Inch B/W (A)](https://www.waveshare.com/product/2.13inch-e-paper-hat.htm) | Black, White | ✕ | ✔ | | |
| [2.9 Inch B/W (A)](https://www.waveshare.com/product/2.9inch-e-paper-module.htm) | Black, White | ✕ | ✔ | ✔ | ✔ [[3](#3-29-inch-e-ink-blackwhite---tests)] |
| [2.9 Inch B/W (A)](https://www.waveshare.com/product/2.9inch-e-paper-module.htm) | Black, White | ✕ | ✔ | ✔ | ✔ |
| [1.54 Inch B/W/R (B)](https://www.waveshare.com/product/modules/oleds-lcds/e-paper/1.54inch-e-paper-module-b.htm) | Black, White, Red | ✕ | ✕ | ✔ | ✔ |
### [1]: 7.5 Inch B/W V2 (A)
@ -62,10 +62,6 @@ Out of the Box the original driver from Waveshare only supports full updates.
That means: Be careful with the quick refresh updates: <br>
It's possible with this driver but might lead to ghosting / burn-in effects therefore it's hidden behind a feature.
### [3]: 2.9 Inch E-Ink Black/White - Tests
Since my 2.9 Inch Display has some blurring issues I am not absolutly sure if everything was working correctly as it should :-)
### Interface
| Interface | Description |

47
examples/Readme.md

@ -1,47 +0,0 @@
# Examples:
All of these examples are projects of their own.
A few notes:
- If not stated otherwise the example is for a Raspberry Pi running Linux.
- epdXinYY_full showcase most of what can be done with this crate. This means that they are using graphics feature and use the DisplayXinYY with its buffer.
Special Examples:
### epd4in2_var_display_buffer
This examples used the graphics feature with VarDisplay and therefore a variable buffer(size).
### epd1in54_no_graphics (Fastest Example)
This example doesn't use the graphics feature and handles all the "drawing" by itself. It also has a speeddemonstration included.
### epd4in2_full_blue_pill
Connect epd4in2 display to blue pill board:
- BUSY -> A10
- RST -> A9
- DC -> A8
- CS -> B12
- CLK -> B13
- DIN -> B15
- GND -> G
- VCC -> 3.3
For compiling and flashing, please refer to [TeXitois blue pill quickstart](https://github.com/TeXitoi/blue-pill-quickstart/blob/master/README.md).
Basically:
```shell
curl https://sh.rustup.rs -sSf | sh
rustup target add thumbv7m-none-eabi
sudo apt-get install gdb-arm-none-eabi openocd
cd epd4in2_full_blue_pill
# connect ST-Link v2 to the blue pill and the computer
# openocd in another terminal
cargo run --release
```
Ff you can't connect to openocd you might need to adapt your udev rules or use sudo ([openOCD Problems](https://rust-embedded.github.io/discovery/03-setup/linux.html#udev-rules))

13
examples/epd1in54_full/Cargo.toml

@ -1,13 +0,0 @@
[package]
name = "embedded_linux_eink_example"
version = "0.1.0"
authors = ["Christoph Groß <christoph-gross@mailbox.org>"]
edition = "2018"
[dependencies]
epd-waveshare = { path = "../../", default-features = false, features = ["epd1in54", "graphics"]}
linux-embedded-hal = "0.2.2"
embedded-graphics = "0.5.2"
embedded-hal = { version = "0.2.2", features = ["unproven"] }

150
examples/epd1in54_full/src/main.rs

@ -1,150 +0,0 @@
#![deny(warnings)]
use embedded_graphics::{coord::Coord, fonts::Font6x8, prelude::*, Drawing};
use embedded_hal::prelude::*;
use epd_waveshare::{
epd1in54::{Display1in54, EPD1in54},
graphics::{Display, DisplayRotation},
prelude::*,
};
use linux_embedded_hal::{
spidev::{self, SpidevOptions},
sysfs_gpio::Direction,
Delay, Pin, Spidev,
};
// activate spi, gpio in raspi-config
// needs to be run with sudo because of some sysfs_gpio permission problems and follow-up timing problems
// see https://github.com/rust-embedded/rust-sysfs-gpio/issues/5 and follow-up issues
fn main() {
if let Err(e) = run() {
eprintln!("Program exited early with error: {}", e);
}
}
fn run() -> Result<(), std::io::Error> {
// Configure SPI
// SPI settings are from eink-waveshare-rs documenation
let mut spi = Spidev::open("/dev/spidev0.0").expect("spidev directory");
let options = SpidevOptions::new()
.bits_per_word(8)
.max_speed_hz(4_000_000)
.mode(spidev::SPI_MODE_0)
.build();
spi.configure(&options).expect("spi configuration");
// Configure Digital I/O Pin to be used as Chip Select for SPI
let cs_pin = Pin::new(26); //BCM7 CE0
cs_pin.export().expect("cs_pin export");
while !cs_pin.is_exported() {}
cs_pin
.set_direction(Direction::Out)
.expect("cs_pin Direction");
cs_pin.set_value(1).expect("cs_pin Value set to 1");
// Configure Busy Input Pin
let busy = Pin::new(5); //pin 29
busy.export().expect("busy export");
while !busy.is_exported() {}
busy.set_direction(Direction::In).expect("busy Direction");
//busy.set_value(1).expect("busy Value set to 1");
// Configure Data/Command OutputPin
let dc = Pin::new(6); //pin 31 //bcm6
dc.export().expect("dc export");
while !dc.is_exported() {}
dc.set_direction(Direction::Out).expect("dc Direction");
dc.set_value(1).expect("dc Value set to 1");
// Configure Reset OutputPin
let rst = Pin::new(16); //pin 36 //bcm16
rst.export().expect("rst export");
while !rst.is_exported() {}
rst.set_direction(Direction::Out).expect("rst Direction");
rst.set_value(1).expect("rst Value set to 1");
// Configure Delay
let mut delay = Delay {};
// Setup of the needed pins is finished here
// 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)?;
// Clear the full screen
epd.clear_frame(&mut spi).expect("clear frame 1");
epd.display_frame(&mut spi).expect("disp 1");
println!("Test all the rotations");
let mut display = Display1in54::default();
display.set_rotation(DisplayRotation::Rotate0);
display.draw(
Font6x8::render_str("Rotate 0!")
.stroke(Some(Color::Black))
.fill(Some(Color::White))
.translate(Coord::new(5, 50))
.into_iter(),
);
display.set_rotation(DisplayRotation::Rotate90);
display.draw(
Font6x8::render_str("Rotate 90!")
.stroke(Some(Color::Black))
.fill(Some(Color::White))
.translate(Coord::new(5, 50))
.into_iter(),
);
display.set_rotation(DisplayRotation::Rotate180);
display.draw(
Font6x8::render_str("Rotate 180!")
.stroke(Some(Color::Black))
.fill(Some(Color::White))
.translate(Coord::new(5, 50))
.into_iter(),
);
display.set_rotation(DisplayRotation::Rotate270);
display.draw(
Font6x8::render_str("Rotate 270!")
.stroke(Some(Color::Black))
.fill(Some(Color::White))
.translate(Coord::new(5, 50))
.into_iter(),
);
// Display updated frame
epd.update_frame(&mut spi, &display.buffer()).unwrap();
epd.display_frame(&mut spi)
.expect("display frame new graphics");
delay.delay_ms(5000u16);
// a quickly moving `Hello World!`
display.set_rotation(DisplayRotation::Rotate0);
epd.set_lut(&mut spi, Some(RefreshLUT::QUICK))
.expect("SET LUT QUICK error");
let limit = 20;
for i in 0..limit {
println!("Moving Hello World. Loop {} from {}", (i + 1), limit);
display.draw(
Font6x8::render_str(" Hello World! ")
.style(Style {
fill_color: Some(Color::White),
stroke_color: Some(Color::Black),
stroke_width: 0u8, // Has no effect on fonts
})
.translate(Coord::new(5 + i * 6, 50))
.into_iter(),
);
epd.update_frame(&mut spi, &display.buffer()).unwrap();
epd.display_frame(&mut spi)
.expect("display frame new graphics");
}
// Set the EPD to sleep
epd.sleep(&mut spi).expect("sleep");
Ok(())
}

10
examples/epd1in54_no_graphics/src/main.rs → examples/epd1in54_no_graphics.rs

@ -12,20 +12,14 @@ use linux_embedded_hal::{
// needs to be run with sudo because of some sysfs_gpio permission problems and follow-up timing problems
// see https://github.com/rust-embedded/rust-sysfs-gpio/issues/5 and follow-up issues
fn main() {
if let Err(e) = run() {
eprintln!("Program exited early with error: {}", e);
}
}
fn run() -> Result<(), std::io::Error> {
fn main() -> Result<(), std::io::Error> {
// Configure SPI
// SPI settings are from eink-waveshare-rs documenation
let mut spi = Spidev::open("/dev/spidev0.0")?;
let options = SpidevOptions::new()
.bits_per_word(8)
.max_speed_hz(4_000_000)
.mode(spidev::SPI_MODE_0)
.mode(spidev::SpiModeFlags::SPI_MODE_0)
.build();
spi.configure(&options).expect("spi configuration");

12
examples/epd1in54_no_graphics/Cargo.toml

@ -1,12 +0,0 @@
[package]
name = "embedded_linux_eink_example"
version = "0.1.0"
authors = ["Christoph Groß <christoph-gross@mailbox.org>"]
edition = "2018"
[dependencies]
epd-waveshare = { path = "../../", default-features = false, features = ["epd1in54"]}
linux-embedded-hal = "0.2.2"
embedded-hal = { version = "0.2.2", features = ["unproven"] }

13
examples/epd2in9_full/Cargo.toml

@ -1,13 +0,0 @@
[package]
name = "embedded_linux_eink_example"
version = "0.1.0"
authors = ["Christoph Groß <christoph-gross@mailbox.org>"]
edition = "2018"
[dependencies]
epd-waveshare = { path = "../../", default-features = false, features = ["epd2in9", "graphics"]}
linux-embedded-hal = "0.2.2"
embedded-graphics = "0.5.2"
embedded-hal = { version = "0.2.2", features = ["unproven"] }

154
examples/epd2in9_full/src/main.rs

@ -1,154 +0,0 @@
#![deny(warnings)]
use embedded_graphics::{coord::Coord, fonts::Font6x8, prelude::*, Drawing};
use embedded_hal::prelude::*;
use epd_waveshare::{
epd2in9::{Display2in9, EPD2in9},
graphics::{Display, DisplayRotation},
prelude::*,
};
use linux_embedded_hal::{
spidev::{self, SpidevOptions},
sysfs_gpio::Direction,
Delay, Pin, Spidev,
};
// activate spi, gpio in raspi-config
// needs to be run with sudo because of some sysfs_gpio permission problems and follow-up timing problems
// see https://github.com/rust-embedded/rust-sysfs-gpio/issues/5 and follow-up issues
//TODO: Test this implemenation with a new display
fn main() {
if let Err(e) = run() {
eprintln!("Program exited early with error: {}", e);
}
}
fn run() -> Result<(), std::io::Error> {
// Configure SPI
// SPI settings are from eink-waveshare-rs documenation
let mut spi = Spidev::open("/dev/spidev0.0").expect("spidev directory");
let options = SpidevOptions::new()
.bits_per_word(8)
.max_speed_hz(4_000_000)
.mode(spidev::SPI_MODE_0)
.build();
spi.configure(&options).expect("spi configuration");
// Configure Digital I/O Pin to be used as Chip Select for SPI
let cs_pin = Pin::new(26); //BCM7 CE0
cs_pin.export().expect("cs_pin export");
while !cs_pin.is_exported() {}
cs_pin
.set_direction(Direction::Out)
.expect("cs_pin Direction");
cs_pin.set_value(1).expect("cs_pin Value set to 1");
// Configure Busy Input Pin
let busy = Pin::new(5); //pin 29
busy.export().expect("busy export");
while !busy.is_exported() {}
busy.set_direction(Direction::In).expect("busy Direction");
//busy.set_value(1).expect("busy Value set to 1");
// Configure Data/Command OutputPin
let dc = Pin::new(6); //pin 31 //bcm6
dc.export().expect("dc export");
while !dc.is_exported() {}
dc.set_direction(Direction::Out).expect("dc Direction");
dc.set_value(1).expect("dc Value set to 1");
// Configure Reset OutputPin
let rst = Pin::new(16); //pin 36 //bcm16
rst.export().expect("rst export");
while !rst.is_exported() {}
rst.set_direction(Direction::Out).expect("rst Direction");
rst.set_value(1).expect("rst Value set to 1");
// Configure Delay
let mut delay = Delay {};
// Setup of the needed pins is finished here
// Now the "real" usage of the eink-waveshare-rs crate begins
let mut epd = EPD2in9::new(&mut spi, cs_pin, busy, dc, rst, &mut delay)?;
// Clear the full screen
epd.clear_frame(&mut spi).expect("clear frame 1");
epd.display_frame(&mut spi).expect("disp 1");
println!("Test all the rotations");
let mut display = Display2in9::default();
epd.update_frame(&mut spi, display.buffer()).unwrap();
epd.display_frame(&mut spi).expect("display frame x03");
display.set_rotation(DisplayRotation::Rotate0);
display.draw(
Font6x8::render_str("Rotate 0!")
.stroke(Some(Color::Black))
.fill(Some(Color::White))
.translate(Coord::new(5, 50))
.into_iter(),
);
display.set_rotation(DisplayRotation::Rotate90);
display.draw(
Font6x8::render_str("Rotate 90!")
.stroke(Some(Color::Black))
.fill(Some(Color::White))
.translate(Coord::new(5, 50))
.into_iter(),
);
display.set_rotation(DisplayRotation::Rotate180);
display.draw(
Font6x8::render_str("Rotate 180!")
.stroke(Some(Color::Black))
.fill(Some(Color::White))
.translate(Coord::new(5, 50))
.into_iter(),
);
display.set_rotation(DisplayRotation::Rotate270);
display.draw(
Font6x8::render_str("Rotate 270!")
.stroke(Some(Color::Black))
.fill(Some(Color::White))
.translate(Coord::new(5, 50))
.into_iter(),
);
// Display updated frame
epd.update_frame(&mut spi, &display.buffer()).unwrap();
epd.display_frame(&mut spi)
.expect("display frame new graphics");
delay.delay_ms(5000u16);
// a quickly moving `Hello World!`
display.set_rotation(DisplayRotation::Rotate0);
epd.set_lut(&mut spi, Some(RefreshLUT::QUICK))
.expect("SET LUT QUICK error");
let limit = 20;
for i in 0..limit {
println!("Moving Hello World. Loop {} from {}", (i + 1), limit);
display.draw(
Font6x8::render_str(" Hello World! ")
.style(Style {
fill_color: Some(Color::White),
stroke_color: Some(Color::Black),
stroke_width: 0u8, // Has no effect on fonts
})
.translate(Coord::new(5 + i * 6, 50))
.into_iter(),
);
epd.update_frame(&mut spi, &display.buffer()).unwrap();
epd.display_frame(&mut spi)
.expect("display frame new graphics");
}
// Set the EPD to sleep
epd.sleep(&mut spi).expect("sleep");
Ok(())
}

150
examples/epd4in2.rs

@ -0,0 +1,150 @@
#![deny(warnings)]
use embedded_graphics::{
fonts::{Font12x16, Font6x8, Text},
prelude::*,
primitives::{Circle, Line},
style::PrimitiveStyle,
text_style,
};
use embedded_hal::prelude::*;
use epd_waveshare::{
color::*,
epd4in2::{Display4in2, EPD4in2},
graphics::{Display, DisplayRotation},
prelude::*,
};
use linux_embedded_hal::{
spidev::{self, SpidevOptions},
sysfs_gpio::Direction,
Delay, Pin, Spidev,
};
// activate spi, gpio in raspi-config
// needs to be run with sudo because of some sysfs_gpio permission problems and follow-up timing problems
// see https://github.com/rust-embedded/rust-sysfs-gpio/issues/5 and follow-up issues
fn main() -> Result<(), std::io::Error> {
// Configure SPI
// Settings are taken from
let mut spi = Spidev::open("/dev/spidev0.0").expect("spidev directory");
let options = SpidevOptions::new()
.bits_per_word(8)
.max_speed_hz(4_000_000)
.mode(spidev::SpiModeFlags::SPI_MODE_0)
.build();
spi.configure(&options).expect("spi configuration");
// Configure Digital I/O Pin to be used as Chip Select for SPI
let cs = Pin::new(26); //BCM7 CE0
cs.export().expect("cs export");
while !cs.is_exported() {}
cs.set_direction(Direction::Out).expect("CS Direction");
cs.set_value(1).expect("CS Value set to 1");
let busy = Pin::new(5); //pin 29
busy.export().expect("busy export");
while !busy.is_exported() {}
busy.set_direction(Direction::In).expect("busy Direction");
//busy.set_value(1).expect("busy Value set to 1");
let dc = Pin::new(6); //pin 31 //bcm6
dc.export().expect("dc export");
while !dc.is_exported() {}
dc.set_direction(Direction::Out).expect("dc Direction");
dc.set_value(1).expect("dc Value set to 1");
let rst = Pin::new(16); //pin 36 //bcm16
rst.export().expect("rst export");
while !rst.is_exported() {}
rst.set_direction(Direction::Out).expect("rst Direction");
rst.set_value(1).expect("rst Value set to 1");
let mut delay = Delay {};
let mut epd4in2 =
EPD4in2::new(&mut spi, cs, busy, dc, rst, &mut delay).expect("eink initalize error");
//println!("Test all the rotations");
let mut display = Display4in2::default();
display.set_rotation(DisplayRotation::Rotate0);
draw_text(&mut display, "Rotate 0!", 5, 50);
display.set_rotation(DisplayRotation::Rotate90);
draw_text(&mut display, "Rotate 90!", 5, 50);
display.set_rotation(DisplayRotation::Rotate180);
draw_text(&mut display, "Rotate 180!", 5, 50);
display.set_rotation(DisplayRotation::Rotate270);
draw_text(&mut display, "Rotate 270!", 5, 50);
epd4in2.update_frame(&mut spi, &display.buffer())?;
epd4in2
.display_frame(&mut spi)
.expect("display frame new graphics");
delay.delay_ms(5000u16);
//println!("Now test new graphics with default rotation and some special stuff:");
display.clear_buffer(Color::White);
// draw a analog clock
let _ = Circle::new(Point::new(64, 64), 64)
.into_styled(PrimitiveStyle::with_stroke(Black, 1))
.draw(&mut display);
let _ = Line::new(Point::new(64, 64), Point::new(0, 64))
.into_styled(PrimitiveStyle::with_stroke(Black, 1))
.draw(&mut display);
let _ = Line::new(Point::new(64, 64), Point::new(80, 80))
.into_styled(PrimitiveStyle::with_stroke(Black, 1))
.draw(&mut display);
// draw white on black background
let _ = Text::new("It's working-WoB!", Point::new(175, 250))
.into_styled(text_style!(
font = Font6x8,
text_color = White,
background_color = Black
))
.draw(&mut display);
// use bigger/different font
let _ = Text::new("It's working-WoB!", Point::new(50, 200))
.into_styled(text_style!(
font = Font12x16,
text_color = White,
background_color = Black
))
.draw(&mut display);
// a moving `Hello World!`
let limit = 10;
epd4in2.set_lut(&mut spi, Some(RefreshLUT::QUICK)).unwrap();
epd4in2.clear_frame(&mut spi).unwrap();
for i in 0..limit {
//println!("Moving Hello World. Loop {} from {}", (i + 1), limit);
draw_text(&mut display, " Hello World! ", 5 + i * 12, 50);
epd4in2.update_frame(&mut spi, &display.buffer()).unwrap();
epd4in2
.display_frame(&mut spi)
.expect("display frame new graphics");
delay.delay_ms(1_000u16);
}
println!("Finished tests - going to sleep");
epd4in2.sleep(&mut spi)
}
fn draw_text(display: &mut Display4in2, text: &str, x: i32, y: i32) {
let _ = Text::new(text, Point::new(x, y))
.into_styled(text_style!(
font = Font6x8,
text_color = Black,
background_color = White
))
.draw(display);
}

15
examples/epd4in2_full/Cargo.toml

@ -1,15 +0,0 @@
[package]
name = "embedded_linux_eink_example"
version = "0.1.0"
authors = ["Christoph Groß <christoph-gross@mailbox.org>"]
edition = "2018"
[dependencies]
## The Only difference between this one and the one without default features sizewise seems to be a different .d-file Size (dependencies-file)
#epd_waveshare = { path = "../../"}
epd-waveshare = { path = "../../", default-features = false, features = ["epd4in2", "graphics"]}
linux-embedded-hal = "0.2.2"
embedded-graphics = "0.5.2"
embedded-hal = { version = "0.2.2", features = ["unproven"] }

189
examples/epd4in2_full/src/main.rs

@ -1,189 +0,0 @@
#![deny(warnings)]
use embedded_graphics::{
coord::Coord,
fonts::{Font12x16, Font6x8},
prelude::*,
primitives::{Circle, Line},
Drawing,
};
use embedded_hal::prelude::*;
use epd_waveshare::{
epd4in2::{Display4in2, EPD4in2},
graphics::{Display, DisplayRotation},
prelude::*,
};
use linux_embedded_hal::{
spidev::{self, SpidevOptions},
sysfs_gpio::Direction,
Delay, Pin, Spidev,
};
// activate spi, gpio in raspi-config
// needs to be run with sudo because of some sysfs_gpio permission problems and follow-up timing problems
// see https://github.com/rust-embedded/rust-sysfs-gpio/issues/5 and follow-up issues
fn main() {
if let Err(e) = run() {
eprintln!("Program exited early with error: {}", e);
}
}
fn run() -> Result<(), std::io::Error> {
// Configure SPI
// Settings are taken from
let mut spi = Spidev::open("/dev/spidev0.0").expect("spidev directory");
let options = SpidevOptions::new()
.bits_per_word(8)
.max_speed_hz(4_000_000)
.mode(spidev::SPI_MODE_0)
.build();
spi.configure(&options).expect("spi configuration");
// Configure Digital I/O Pin to be used as Chip Select for SPI
let cs = Pin::new(26); //BCM7 CE0
cs.export().expect("cs export");
while !cs.is_exported() {}
cs.set_direction(Direction::Out).expect("CS Direction");
cs.set_value(1).expect("CS Value set to 1");
let busy = Pin::new(5); //pin 29
busy.export().expect("busy export");
while !busy.is_exported() {}
busy.set_direction(Direction::In).expect("busy Direction");
//busy.set_value(1).expect("busy Value set to 1");
let dc = Pin::new(6); //pin 31 //bcm6
dc.export().expect("dc export");
while !dc.is_exported() {}
dc.set_direction(Direction::Out).expect("dc Direction");
dc.set_value(1).expect("dc Value set to 1");
let rst = Pin::new(16); //pin 36 //bcm16
rst.export().expect("rst export");
while !rst.is_exported() {}
rst.set_direction(Direction::Out).expect("rst Direction");
rst.set_value(1).expect("rst Value set to 1");
let mut delay = Delay {};
let mut epd4in2 =
EPD4in2::new(&mut spi, cs, busy, dc, rst, &mut delay).expect("eink initalize error");
println!("Test all the rotations");
let mut display = Display4in2::default();
display.set_rotation(DisplayRotation::Rotate0);
display.draw(
Font6x8::render_str("Rotate 0!")
.stroke(Some(Color::Black))
.fill(Some(Color::White))
.translate(Coord::new(5, 50))
.into_iter(),
);
display.set_rotation(DisplayRotation::Rotate90);
display.draw(
Font6x8::render_str("Rotate 90!")
.stroke(Some(Color::Black))
.fill(Some(Color::White))
.translate(Coord::new(5, 50))
.into_iter(),
);
display.set_rotation(DisplayRotation::Rotate180);
display.draw(
Font6x8::render_str("Rotate 180!")
.stroke(Some(Color::Black))
.fill(Some(Color::White))
.translate(Coord::new(5, 50))
.into_iter(),
);
display.set_rotation(DisplayRotation::Rotate270);
display.draw(
Font6x8::render_str("Rotate 270!")
.stroke(Some(Color::Black))
.fill(Some(Color::White))
.translate(Coord::new(5, 50))
.into_iter(),
);
epd4in2.update_frame(&mut spi, &display.buffer()).unwrap();
epd4in2
.display_frame(&mut spi)
.expect("display frame new graphics");
delay.delay_ms(5000u16);
println!("Now test new graphics with default rotation and some special stuff:");
display.clear_buffer(Color::White);
// draw a analog clock
display.draw(
Circle::new(Coord::new(64, 64), 64)
.stroke(Some(Color::Black))
.into_iter(),
);
display.draw(
Line::new(Coord::new(64, 64), Coord::new(0, 64))
.stroke(Some(Color::Black))
.into_iter(),
);
display.draw(
Line::new(Coord::new(64, 64), Coord::new(80, 80))
.stroke(Some(Color::Black))
.into_iter(),
);
// draw white on black background
display.draw(
Font6x8::render_str("It's working-WoB!")
// Using Style here
.style(Style {
fill_color: Some(Color::Black),
stroke_color: Some(Color::White),
stroke_width: 0u8, // Has no effect on fonts
})
.translate(Coord::new(175, 250))
.into_iter(),
);
// use bigger/different font
display.draw(
Font12x16::render_str("It's working-BoW!")
// Using Style here
.style(Style {
fill_color: Some(Color::White),
stroke_color: Some(Color::Black),
stroke_width: 0u8, // Has no effect on fonts
})
.translate(Coord::new(50, 200))
.into_iter(),
);
// a moving `Hello World!`
let limit = 10;
for i in 0..limit {
println!("Moving Hello World. Loop {} from {}", (i + 1), limit);
display.draw(
Font6x8::render_str(" Hello World! ")
.style(Style {
fill_color: Some(Color::White),
stroke_color: Some(Color::Black),
stroke_width: 0u8, // Has no effect on fonts
})
.translate(Coord::new(5 + i * 12, 50))
.into_iter(),
);
epd4in2.update_frame(&mut spi, &display.buffer()).unwrap();
epd4in2
.display_frame(&mut spi)
.expect("display frame new graphics");
delay.delay_ms(1_000u16);
}
println!("Finished tests - going to sleep");
epd4in2.sleep(&mut spi)
}

12
examples/epd4in2_full_blue_pill/.cargo/config

@ -1,12 +0,0 @@
[target.thumbv7m-none-eabi]
# uncomment ONE of these three option to make `cargo run` start a GDB session
# which option to pick depends on your system
runner = "arm-none-eabi-gdb -q -x openocd.gdb"
# runner = "gdb-multiarch -q -x openocd.gdb"
# runner = "gdb -q -x openocd.gdb"
rustflags = ["-C", "link-arg=-Tlink.x"]
[build]
target = "thumbv7m-none-eabi"

19
examples/epd4in2_full_blue_pill/Cargo.toml

@ -1,19 +0,0 @@
[package]
name = "embedded_linux_eink_example"
version = "0.1.0"
authors = ["Christoph Groß <christoph-gross@mailbox.org>"]
edition = "2018"
[dependencies]
## The Only difference between this one and the one without default features sizewise seems to be a different .d-file Size (dependencies-file)
#epd_waveshare = { path = "../../"}
epd-waveshare = { path = "../../", default-features = false, features = ["epd4in2", "graphics"]}
embedded-graphics = "0.5.2"
embedded-hal = { version = "0.2.2", features = ["unproven"] }
stm32f1xx-hal = { version = "0.2", features = ["rt", "stm32f103" ] }
cortex-m = "0.5.0"
cortex-m-rt = { version = "0.6.6", features = ["device"] }
panic-semihosting = "0.5"

6
examples/epd4in2_full_blue_pill/memory.x

@ -1,6 +0,0 @@
/* Linker script for the STM32F103C8T6 */
MEMORY
{
FLASH : ORIGIN = 0x08000000, LENGTH = 64K
RAM : ORIGIN = 0x20000000, LENGTH = 20K
}

2
examples/epd4in2_full_blue_pill/openocd.cfg

@ -1,2 +0,0 @@
source [find interface/stlink-v2.cfg]
source [find target/stm32f1x.cfg]

10
examples/epd4in2_full_blue_pill/openocd.gdb

@ -1,10 +0,0 @@
target remote :3333
set print asm-demangle on
monitor arm semihosting enable
# detect unhandled exceptions, hard faults and panics
break DefaultHandler
break HardFault
break rust_begin_unwind
load

192
examples/epd4in2_full_blue_pill/src/main.rs

@ -1,192 +0,0 @@
#![no_main]
#![no_std]
// set the panic handler
#[allow(unused_imports)]
use panic_semihosting;
use cortex_m_rt::entry;
use stm32f1xx_hal::prelude::*;
use stm32f1xx_hal::{delay, spi};
use embedded_graphics::{
coord::Coord,
fonts::{Font12x16, Font6x8},
prelude::*,
primitives::{Circle, Line},
Drawing,
};
use epd_waveshare::{
epd4in2::Display4in2,
graphics::{Display, DisplayRotation},
prelude::*,
};
#[entry]
fn main() -> ! {
let core = cortex_m::Peripherals::take().unwrap();
let device = stm32f1xx_hal::stm32::Peripherals::take().unwrap();
let mut rcc = device.RCC.constrain();
let mut flash = device.FLASH.constrain();
let clocks = rcc
.cfgr
.use_hse(8.mhz())
.sysclk(72.mhz())
.pclk1(36.mhz())
.freeze(&mut flash.acr);
let mut gpioa = device.GPIOA.split(&mut rcc.apb2);
let mut gpiob = device.GPIOB.split(&mut rcc.apb2);
let mut delay = delay::Delay::new(core.SYST, clocks);
// spi setup
let sck = gpiob.pb13.into_alternate_push_pull(&mut gpiob.crh);
let miso = gpiob.pb14;
let mosi = gpiob.pb15.into_alternate_push_pull(&mut gpiob.crh);
let mut spi = spi::Spi::spi2(
device.SPI2,
(sck, miso, mosi),
epd_waveshare::SPI_MODE,
4.mhz(),
clocks,
&mut rcc.apb1,
);
// epd setup
let mut epd4in2 = epd_waveshare::epd4in2::EPD4in2::new(
&mut spi,
gpiob.pb12.into_push_pull_output(&mut gpiob.crh),
gpioa.pa10.into_floating_input(&mut gpioa.crh),
gpioa.pa8.into_push_pull_output(&mut gpioa.crh),
gpioa.pa9.into_push_pull_output(&mut gpioa.crh),
&mut delay,
)
.unwrap();
epd4in2.set_lut(&mut spi, Some(RefreshLUT::QUICK)).unwrap();
epd4in2.clear_frame(&mut spi).unwrap();
//println!("Test all the rotations");
let mut display = Display4in2::default();
display.set_rotation(DisplayRotation::Rotate0);
display.draw(
Font6x8::render_str("Rotate 0!")
.stroke(Some(Color::Black))
.fill(Some(Color::White))
.translate(Coord::new(5, 50))
.into_iter(),
);
display.set_rotation(DisplayRotation::Rotate90);
display.draw(
Font6x8::render_str("Rotate 90!")
.stroke(Some(Color::Black))
.fill(Some(Color::White))
.translate(Coord::new(5, 50))
.into_iter(),
);
display.set_rotation(DisplayRotation::Rotate180);
display.draw(
Font6x8::render_str("Rotate 180!")
.stroke(Some(Color::Black))
.fill(Some(Color::White))
.translate(Coord::new(5, 50))
.into_iter(),
);
display.set_rotation(DisplayRotation::Rotate270);
display.draw(
Font6x8::render_str("Rotate 270!")
.stroke(Some(Color::Black))
.fill(Some(Color::White))
.translate(Coord::new(5, 50))
.into_iter(),
);
epd4in2.update_frame(&mut spi, &display.buffer()).unwrap();
epd4in2
.display_frame(&mut spi)
.expect("display frame new graphics");
delay.delay_ms(5000u16);
//println!("Now test new graphics with default rotation and some special stuff:");
display.clear_buffer(Color::White);
// draw a analog clock
display.draw(
Circle::new(Coord::new(64, 64), 64)
.stroke(Some(Color::Black))
.into_iter(),
);
display.draw(
Line::new(Coord::new(64, 64), Coord::new(0, 64))
.stroke(Some(Color::Black))
.into_iter(),
);
display.draw(
Line::new(Coord::new(64, 64), Coord::new(80, 80))
.stroke(Some(Color::Black))
.into_iter(),
);
// draw white on black background
display.draw(
Font6x8::render_str("It's working-WoB!")
// Using Style here
.style(Style {
fill_color: Some(Color::Black),
stroke_color: Some(Color::White),
stroke_width: 0u8, // Has no effect on fonts
})
.translate(Coord::new(175, 250))
.into_iter(),
);
// use bigger/different font
display.draw(
Font12x16::render_str("It's working-BoW!")
// Using Style here
.style(Style {
fill_color: Some(Color::White),
stroke_color: Some(Color::Black),
stroke_width: 0u8, // Has no effect on fonts
})
.translate(Coord::new(50, 200))
.into_iter(),
);
// a moving `Hello World!`
let limit = 10;
epd4in2.set_lut(&mut spi, Some(RefreshLUT::QUICK)).unwrap();
epd4in2.clear_frame(&mut spi).unwrap();
for i in 0..limit {
//println!("Moving Hello World. Loop {} from {}", (i + 1), limit);
display.draw(
Font6x8::render_str(" Hello World! ")
.style(Style {
fill_color: Some(Color::White),
stroke_color: Some(Color::Black),
stroke_width: 0u8, // Has no effect on fonts
})
.translate(Coord::new(5 + i * 12, 50))
.into_iter(),
);
epd4in2.update_frame(&mut spi, &display.buffer()).unwrap();
epd4in2
.display_frame(&mut spi)
.expect("display frame new graphics");
delay.delay_ms(1_000u16);
}
//println!("Finished tests - going to sleep");
epd4in2.sleep(&mut spi).expect("epd goes to sleep");
loop {
// sleep
cortex_m::asm::wfi();
}
}

15
examples/epd4in2_var_display_buffer/Cargo.toml

@ -1,15 +0,0 @@
[package]
name = "embedded_linux_eink_example"
version = "0.1.0"
authors = ["Christoph Groß <christoph-gross@mailbox.org>"]
edition = "2018"
[dependencies]
## The Only difference between this one and the one without default features sizewise seems to be a different .d-file Size (dependencies-file)
#epd_waveshare = { path = "../../"}
epd-waveshare = { path = "../../", default-features = false, features = ["epd4in2", "graphics"]}
linux-embedded-hal = "0.2.2"
embedded-graphics = "0.5.2"
embedded-hal = { version = "0.2.2", features = ["unproven"] }

139
examples/epd4in2_var_display_buffer/src/main.rs → examples/epd4in2_variable_size.rs

@ -1,14 +1,16 @@
#![deny(warnings)]
#![deny(warnings)]
use embedded_graphics::{
coord::Coord,
fonts::{Font12x16, Font6x8},
fonts::{Font12x16, Font6x8, Text},
prelude::*,
primitives::{Circle, Line},
Drawing,