Giter VIP home page Giter VIP logo

epd-waveshare's People

Contributors

akashihi avatar alexx-g avatar andber1 avatar asaaki avatar belak avatar buggstream avatar caemor avatar crzysdrs avatar cyanblob avatar david-oconnor avatar dbr avatar dkm avatar icewind1991 avatar jcard0na avatar jetjinser avatar jkristell avatar lrbalt avatar marcelbuesing avatar michaelbeaumont avatar newam avatar olback avatar peckpeck avatar pjsier avatar reinoutheeck avatar shymega avatar sirhcel avatar str4d avatar vhdirk avatar whiite avatar wsndshx avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

epd-waveshare's Issues

Please help me with this almost-working example (EPD1in54)

I'm trying to get Rust working on the Watchy: watchy.sqfmi.com .

I've gotten everything to compile and even flash, and even clear the screen! But nothing beyond that.

I'm wondering why drawing doesn't work at all. I'm not sure what to think - this is all new to me.

I've attached my code, in hopes that with some expertise, this is trivial to fix.

#![no_std]
#![no_main]

use xtensa_lx_rt as _;
use xtensa_lx_rt::entry;
use panic_halt as _;
use esp32_hal::{
  prelude::*,
  dport::Split,
  target,
  gpio::*,
  delay::Delay,
};

use epd_waveshare::{epd1in54::*, prelude::*};

#[entry]
fn main() -> ! {
  let p = target::Peripherals::take().unwrap();

  let (_, dport_clock_control) = p.DPORT.split();

  let clkcntrl = esp32_hal::clock_control::ClockControl::new(
      p.RTCCNTL,
      p.APB_CTRL,
      dport_clock_control,
      esp32_hal::clock_control::XTAL_FREQUENCY_AUTO,
  )
  .unwrap();

  let (clkcntrl_config, _) = clkcntrl.freeze().unwrap();

  let gpios = p.GPIO.split();
  let gpio18 = gpios.gpio18.into_push_pull_output();
  let gpio23 = gpios.gpio23.into_push_pull_output();
  let gpio5 = gpios.gpio5.into_push_pull_output();
  let gpio19 = gpios.gpio19.into_pull_up_input();
  let gpio10 = gpios.gpio10.into_push_pull_output();
  let gpio9 = gpios.gpio9.into_push_pull_output();

  let mut spi = esp32_hal::spi::SPI::<
    target::SPI3,
    Gpio18<Output<PushPull>>,
    Gpio23<Output<PushPull>>,
    Gpio1<Input<PullUp>>, // Not actually used...?
    Gpio5<Output<PushPull>>
  >::new(
    p.SPI3,
    esp32_hal::spi::Pins {
      sclk: gpio18,
      sdo: gpio23,
      sdi: None, // No SDI needed by the epaper display
      cs: None, // Used below?
    },
    esp32_hal::spi::config::Config {
      baudrate: 2_000_000.Hz(),
      data_mode: esp32_hal::spi::config::MODE_0,
      bit_order: esp32_hal::spi::config::BitOrder::MSBFirst,
    },
    clkcntrl_config,
  ).unwrap();

  let mut delay = Delay::new();
  delay.delay_ms(5000u16);
  let mut epd = EPD1in54::new(&mut spi, gpio5, gpio19, gpio10, gpio9, &mut delay).unwrap();

  // Clear the full screen
  epd.clear_frame(&mut spi);
  epd.display_frame(&mut spi);

  // Speeddemo
  epd.set_lut(&mut spi, Some(RefreshLUT::QUICK));
  let small_buffer = [Color::Black.get_byte_value(); 32]; //16x16
  let number_of_runs = 1;
  for i in 0..number_of_runs {
      let offset = i * 8 % 150;
      epd.update_partial_frame(&mut spi, &small_buffer, 25 + offset, 25 + offset, 16, 16);
      epd.display_frame(&mut spi);
  }

  // Clear the full screen
  epd.clear_frame(&mut spi);
  epd.display_frame(&mut spi);

  // Draw some squares
  let small_buffer = [Color::Black.get_byte_value(); 3200]; //160x160
  epd.update_partial_frame(&mut spi, &small_buffer, 20, 20, 160, 160);

  let small_buffer = [Color::White.get_byte_value(); 800]; //80x80
  epd.update_partial_frame(&mut spi, &small_buffer, 60, 60, 80, 80);

  let small_buffer = [Color::Black.get_byte_value(); 8]; //8x8
  epd.update_partial_frame(&mut spi, &small_buffer, 96, 96, 8, 8);

  // Display updated frame
  epd.display_frame(&mut spi);
  delay.delay_ms(5000u16);

  // Set the EPD to sleep
  epd.sleep(&mut spi);

  loop {}
}

Buffer/Iterators Improvements

For the two last points:

Current situation:

  1. iterator-based drawing - through embedded-graphics lib
  2. fills "randomly" positioned pixel in bigger buffer (u8-slice) - this happens in Drawable::draw()
  3. Transmit full buffer via spi

What could be changed and improved:

  1. nothing
    2.1 Fill full byte of 8 pixels (u8) and transmit the iterator of these bytes? questionable
    2.2 Use Dimensions traits to only transmit the necessary parts to limit the changed parts and only draw these with update_partial_frame
  2. transmit iterator via spi (this would make the linux chunk size limit unecessary)

`background_color` is misused on color displays

For some reason, all of the color displays seem to be using their background color as the color to set the chromatic layer to when rendering in black-and-white. This means that if their background color is set to black, the whole display gets set to red. (Also, after doing that by accident, it seems to have permanently washed out my display's red color; it might be because it was trying to set a pixel to black and red at the same time?)
On top of that, a lot of them don't actually use it as the color to clear the display in clear_frame either, just using the default background color.

As an aside, background_color seems a bit odd in general; it's only used for clear_frame, and doesn't actually affect the background color when rendering with embedded-graphics. Is it really needed?

cannot compile epd-waveshare (overflow error)

Disabling default features removes the error.

$ cargo build
    Updating crates.io index
   Compiling epd-waveshare v0.5.0
error[E0080]: evaluation of constant value failed
  --> /home/jonathan/.cargo/registry/src/github.com-1ecc6299db9ec823/epd-waveshare-0.5.0/src/epd4in2/graphics.rs:11:18
   |
11 |     buffer: [u8; WIDTH as usize * HEIGHT as usize / 8],
   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to compute `400_usize * 300_usize`, which would overflow

error[E0080]: evaluation of constant value failed
  --> /home/jonathan/.cargo/registry/src/github.com-1ecc6299db9ec823/epd-waveshare-0.5.0/src/epd5in65f/graphics.rs:11:18
   |
11 |     buffer: [u8; WIDTH as usize * HEIGHT as usize / 2],
   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to compute `600_usize * 448_usize`, which would overflow

error[E0080]: evaluation of constant value failed
  --> /home/jonathan/.cargo/registry/src/github.com-1ecc6299db9ec823/epd-waveshare-0.5.0/src/epd7in5/graphics.rs:11:18
   |
11 |     buffer: [u8; WIDTH as usize * HEIGHT as usize / 8],
   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to compute `640_usize * 384_usize`, which would overflow

error[E0080]: evaluation of constant value failed
  --> /home/jonathan/.cargo/registry/src/github.com-1ecc6299db9ec823/epd-waveshare-0.5.0/src/epd7in5_hd/graphics.rs:11:18
   |
11 |     buffer: [u8; WIDTH as usize * HEIGHT as usize / 8],
   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to compute `880_usize * 528_usize`, which would overflow

error[E0080]: evaluation of constant value failed
  --> /home/jonathan/.cargo/registry/src/github.com-1ecc6299db9ec823/epd-waveshare-0.5.0/src/epd7in5_v2/graphics.rs:11:18
   |
11 |     buffer: [u8; WIDTH as usize * HEIGHT as usize / 8],
   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to compute `800_usize * 480_usize`, which would overflow

For more information about this error, try `rustc --explain E0080`.
error: could not compile `epd-waveshare` due to 5 previous errors
# Cargo.toml
[dependencies]
ufmt = "0.1.0"
crc = "3.0.1"
panic-halt = "0.2.0"
embedded-graphics = "0.7.1"
epd-waveshare = "0.5.0"

[dependencies.arduino-hal]
git = "https://github.com/rahix/avr-hal"
rev = "4c9c44c314eb061ee20556ef10d45dea36e75ee4"
features = ["arduino-nano"]

[dependencies.avr-device]
version = "0.5" 
$ rustup override set nightly
info: using existing install for 'nightly-x86_64-unknown-linux-gnu'
info: override toolchain for '/home/jonathan/Documents/Programming/Git/schalter-lampen' set to 'nightly-x86_64-unknown-linux-gnu'

  nightly-x86_64-unknown-linux-gnu unchanged - rustc 1.69.0-nightly (246eae2fa 2023-02-21)

Unable to compile test suite on windows host

Dev build depends on linux-embedded-hal which brings non-portable crates, such as gpio-cdev, spidev, sysfs-gpio and serial-unix which prevents compilation and execution of unit tests on windows.

As linux-embedded-hal is only used for the example code, both example code build and linux-embedded-hal dependency could be a default feature, which can be disabled on the windows platform.

Note about const generics

There's a note in WaveshareDisplay::draw_helper:

/// Becomes uneccesary when const_generics become stablised
fn draw_helper(

min_const_generics was stabilised in rust 1.51, so this could probably be resolved if that's an acceptable MSRV; what's it referring to?
Is it the duplication of Display for each model?

Error running 4.2" using an STM32F3

Are there any tricks on the 4.2" using an STM32F3? Getting no signs of life from the display, and the program crashing once I hit the let mut display = Display4in2::default(); line.

Then you most likely don't have enough ram left over. It needs 15kB for the full default display buffer and the Display4in2::default() doesn't do much besides making a 15kB framebuffer. You could look into the examples/epd4in2_variable_size.rs example which is using a smaller buffer to update only little parts of the display.

You could also check how much ram you have left and try to reduce your usage elsewhere.

Thank you. It also looks like this command: let mut epd = EPD4in2::new(&mut spi, cs_disp, busy, dc, rst, &mut delay).expect("eink initalize error"); is crashing it as well. I think I need to figure out how to set up panics to see what's going on.

Originally posted by @David-OConnor in #47 (comment)


edit: Given that you mentioned they updated the examples to v2, and I can get the arduino example to work on V1 but not V2, maybe I need to see what V1 looks look.

by David-OConnor


From my experience, the "original" version of this crate (without my modifications) worked well with this display except for quick refresh. I did also have the issues with RAM size, though.
Given that the display protocol is write-only, errors during initialization should be limited to errors from your SPI/GPIO HAL implementation.

by mgottschlag

7.5" V2 display driver does not work

A few things I found while trying to get my display to work as expected:

  • epd7in5_v2v::EPD7in5::new(...) hangs here since the wait_until_idle implementation is wrong. In the example C code provided by Waveshare one can see that the driver sends a GET_STATUS command and waits 20ms. This seems to be needed otherwise the busy pin wont update which is the root cause to the problem.

  • Black and White seems to have been mixed up. Setting the fill-color to black makes the display white and vice versa. Same thing goes for text colors/background.

A few things that might be important:

  • Cross-compiling from Arch Linux x64_64 to aarch64 with aarch64-linux-gnu-gcc targeting aarch64-unknown-linux-musl.
  • Using the rppal crate with the hal-unproven feature.
  • Running on Raspberry Pi OS 64-bit Beta (Kernel 5.4.51-v8+) on a Raspberry Pi 3b+.

A hacked together version of epd-waveshare can be found here and an example can be found here.

Support for EPD 2in13(D)

Hi! First and foremost, thanks for all the work that been put in to this project!

I have an EPD 2in13 D e-paper, (Datasheet: https://www.waveshare.com/w/upload/5/5b/2.13inch_e-Paper_%28D%29_Datasheet.pdf , Commands(?): https://github.com/waveshare/e-Paper/blob/master/RaspberryPi%26JetsonNano/c/lib/e-Paper/EPD_2in13d.c), and have issues figuring out how to add support for it.

Looking in issue #26 I learned to look at the datasheet to figure out the Commands. However, It's a bit confusing as the example 2in13v2 (https://www.waveshare.com/w/upload/e/e6/2.13inch_e-Paper_Datasheet.pdf) shows the commands with hex values, but it seems omitted for 2in13d?
Do you have any pointers as how to figure out the values?

Thanks!

Support more (Color) Displays? Includes a Howto

I recently ordered a collection of the WaveShare displays, including:

  • 4.2" Yellow/Black/White
  • 4.2" Black/White
  • 4.2" Red/Black/White
  • 7.5" Black/White
  • 5.83" Red/Black White

I'm happy to contribute or help test, as I plan to use these on a couple of embedded devices for my internet of streams project. I was wondering if you had any notes already on where I should be looking to help add support for the color displays.

Use the same color representation for all EPD

The user has to know how EPD implements colors because tricolors have split buffers and the user has to handle it if she doesn't use Display structures.

Moreover Display structures also have to know this too (see the hacky bwrbit in the structure, or the DisplayColorRendering).

I think it should be the only responsibility of epd structures to handle this, we should present a common simple buffer format ti the user for all epds and the specific epd structures should adapt the bits they send to their specific case.

Make drivers usable on devices with little RAM

I want to use the library on a microcontroller with 16KiB SRAM, with the 400x300 pixel 4.2 inch display. The library, however, requires a full frame buffer of 400x300x1bit = 15000Byte, almost as much as the available RAM.

I would suggest the following interface to stream data into the library:

/// Iterator which streams pixels.
///
/// This type removes the need for a full screen buffer and allows usage on very memory-constrained
/// devices such as small microcontrollers.
pub trait DisplayStream {
    /// Returns the next section of pixels.
    fn next<'a>(&'a mut self) -> Option<&'a [u8]>;
}

to be used with a corresponding function in the WaveshareDisplay trait:

/// Transmit a full frame to the SRAM of the EPD from a streaming iterator
fn update_frame_stream<S: DisplayStream>(
    &mut self,
    spi: &mut SPI,
    stream: S,
) -> Result<(), SPI::Error>;

Do you think such an interface would make sense? The implementation in the driver is trivial (I'd add a stream() function to the interface, to replace the data() call previously used to transmit all the data to the display). The old full-buffer interface could even internally be implemented as an iterator returning a single element. However, I'd have to test whether that negatively impacts code size.

If you think that's a good idea, I'd try to clean my code up a bit to create a first draft for further review.

Bytewise vs Blockwise writing of data over SPI

    Got a chance recently to take a look at this and I believe the culprit might be the change made in #83 which writes bytes one at time instead of all at once as reverting this got my 7.5" HD display working again and suspect this may be the case for the V2 too.
    Happy to make a PR to sort this one out but seems like we may need to support both depending on the display, don't suppose we know which screens will need each write method?

Originally posted by @whiite in #70 (comment)

Dividing the dims by 8

Question: What is the purpose of dividing the dims by 8 when creating the buffer? eg:

pub struct Display4in2 {
    buffer: [u8; WIDTH as usize * HEIGHT as usize / 8],
    rotation: DisplayRotation,
}

With this in mind, how should you map pixels to the buffer, given it's not a 1:1 match? Thank you.

When rotating displays dimensions are not getting updated

If you call display.set_rotation(DisplayRotation::Rotate90); or display.set_rotation(DisplayRotation::Rotate270); the display's dimensions (WIDTH/HEIGHT) should be swapped so that embedded-graphics text alignment features can work properly. As things are right now, if you rotate the display 90ยฐ or 270ยฐ only left-aligned text will display properly.

epd1in54_v2 does not show anything until LUT is set.

It seems to me that the init function for epd1in54_v2 does forget to set the lut (Look up table), which means that code does not do anything at all unless epd.set_lut is explicitly called later.

At least my Raspberry pi pico did not draw any of the data i send until I eventually tried calling set_lut.

Sadly, I don't have any experience with ePaper displays and I don't fully understand why this is needed:
The Reference code (4.2) mentions:

setting: Load LUT from OTP
SPI(0x22, 0xb1)

I guess this means init should call cmd_with_data(spi, Command::DisplayUpdateControl2, &[0xb1])?; somewhere?

Should I just try to get it working on my hardware and open a PR if my init does work in a way that the next display_frame-call does something? I don't fully understand what I am doing, but at least it would work then?

If anyone else tried the epd1in54_v2 and did not neet to set_lut explicitly, that would probably mean my software is buggy somewhere.

Adding support for TTGO T5 v2.3.1 ePaper

Hello,
I want to implement support for my 2.13 inch ePaper display that comes with the TTGO T5 v2.3.1.
I found the How-To to add new display support and I think this is something I could do.
However, I have a hard time understanding all the differences between the models and versioning of those displays and consequently I can't find much documentation for my screen (a datasheet).
My board has the DEPG0213BN. I found this datasheet from here but I'm unsure if this even the correct one for my display.
This is the most concrete example driver I could find.

Does anyone have a few ideas? Thanks!

Is-Busy possible error

this gives different results for the devices with different is_busy_low variants. this should be changed to either return false (or true) for both cases. False might be better, because when we get an error we should better just block other stuff than maybe breaking things...

Originally posted by @caemor in https://github.com/caemor/epd-waveshare/diffs

The WaveshareDisplay associated color is not properly documented

Since it is an associated type, most driver implement it as the color type the epd supports.

However since there is a separate WaveshareThreeColorDisplay trait, some driver implement it only as a black and white color and let the 3 colors handling to WaveshareThreeColorDisplay (eg epd1in54c).

We should document and enforce the right behaviour to make sure this is coherent between various implementations.

Lowered contrast when sleeping in epd2in13_v2 (and possibly other EPD's, based on SSD1680)

I'm adding support for the Good Display GDEY0213B74 (same as GDEQ0213B74) display that I will be using in a project. I used the epd2in13_v2 driver as a base as both seem to be based on a SSD1680 (or similar?) controller.

Among things, I found a problem with my display when sleeping: the image was retained, but at a lower contract (albeit slightly).
The original sleep code included:

        // All sample code enables and disables analog/clocks...
        self.set_display_update_control_2(
            spi,
            DisplayUpdateControl2::new()
                .enable_analog()
                .enable_clock()
                .disable_analog()
                .disable_clock(),
        )?;
        self.command(spi, Command::MasterActivation)?;

        self.set_sleep_mode(spi, self.sleep_mode)?;

After calling Command::MasterActivation immediately the device is sent to sleep by set_sleep_mode, resulting in the lowered contrast image. Adding a self.wait_until_idle() before set_sleep_mode fixes the contrast issue with my display. Possibly (probably?) this is also the case with the Waveshare modules (which look to be Good Display devices slapped onto a PCB with and sold with nondescript names i.e. no mention of the original GD part number)?

Note. The whole DisplayUpdateControl2 and MasterActivation sequence in sleep function seems redundant. I don't really know why this sequence is needed, it is not mentioned in the manual and the comment says it was transferred into this crate as it was part of some other sample code.. What's against just removing this code?

Why do we have to handle CS pin

SPI should already handle setting the CS pin during communication, why do we have to handle it inside the library's interface mod ?

3.7in Display Problems

Hey @caemor @jamesmunns ,
Thanks for pointers. I'm still figuring it out. I have some weird issues when I try to test the 3.7 display using a NRF52 board. Things I've checked so far - initialization and display sequence match C/Python examples, tried different LUT provided in those examples, width/height match as well, rotation only affects that tiny area where "circle" is shown.
Have you encountered this kind of effect?
an attempt to draw a circle

I got my hands on RPi and tested waveshare Python snippet with the same display, everything worked as expected. Digging into my implementation.

Originally posted by @Alexx-G in #26 (comment)

'color' is not a good name for black and white, rename it to BiColor/BWColor ?

See @peckpeck's todo from #132

/// Only for the Black/White-Displays
// TODO : 'color' is not a good name for black and white, rename it to BiColor/BWColor ?
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum Color {
    /// Black color
    Black,
    /// White color
    White,
}

Peckpecks BWColor might make the most sense for me in describing an enum with black and white, but I'm open to alternatives.

new release to crates.io

Is it possible to get a new release to crates.io? I'm using the 2in13 display and it would be nice to use it from crates.io instead of github.

plus it's been about a year since the last release so the embedded-graphics versions in crates.io are outdated as well.

EPD super slow in comparison to python library

See #33 for more info. But in short:

This seems to be about twice as slow to write to the screen as the Waveshare Python controller (specifically the July 10 2017 version, which is what I currently have hooked up to my screen), despite using the same panel settings.

Measuring some drawing times (DATA_START_TRANSMISSION_1 + DISPLAY_REFRESH):

* Old Python driver: 24s
  
  * Buffer is 30720 bytes (`= HEIGHT * WIDTH / 8`)
  * Writes 4 data bytes per buffer byte

* Latest Python driver: 30s
  
  * Buffer is `HEIGHT * WIDTH / 4` bytes
  * Writes 2 data bytes per buffer byte

* This Rust driver: 53s
  
  * Buffer is `HEIGHT * WIDTH / 8` bytes
  * Writes 4 data bytes per buffer byte

Tested on a raspberry pi zero w by @str4d

Pin::export() errors out w/ "Device or resource busy"

Looking at the C code I can see that the SYSFS_GPIO_EXPORT() function does the same as the Rust function: it opens the "/sys/class/gpio/export" file and writes the pin number on it, so not sure why it's throwing the error here.

Device

Waveshare 4.2in on RPi4

Repro

Run examples/4in2, with let cs = Pin::new(8) to match the Pi4

  • Version: Tested on both 0.50.0 and latest master
  • Note: C tests from official waveshare repo finish successfully.

Error

thread 'main' panicked at 'cs export: Io(Os { code: 16, kind: ResourceBusy, message: "Device or resource busy" })', src/main.rs:34:17

Troubleshooting

$ gpio read 8
1
sudo lsof /sys/class/gpio/gpio8
lsof: status error on /sys/class/gpio/gpio8: No such file or directory

Other interesting results:

  • Moving the CS Pin export to the bottom, results in the error moving to the bottom, all other pins export successfully
  • Setting an arbitrary pin_num in let cs = Pin::new(); results in the program not erroring out and continuing to the end, but nothing is shown on the screen.
  • Test starts if I don't touch the pin:
let cs = Pin::new(8); //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");

drawing is ok, and the program exits without errors, but I get a bunch of Input/output error on the pi after that, at any keypress, until I restart the pi, and the e-ink screen is not cleared, not even after calling clear_frame()?;, which does not error out.

Need help running the example for 2in13_v2

Hey, thanks for the library!

I am trying to run the example in examples/epd2in13_v2.rs on a raspberry pi 4. The display is directly connected to the pi via the displays header.

I verified the display is working with the official c example from here.

I cloned the repo and tried two ways of running the example via sudo:

sudo env "PATH=$PATH" cargo run --example epd2in13_v2 (from a normal pi user session)

and directly as root with

cargo run --example epd2in13_v2.

However nothing happens, no output is printed to the terminal, and the display stays blank.

Is it possible that the pins are not identical to the "default" pin configuration of the header?

I am really stuck here, any help on how to debug the issue would be much appreciated!

4.2": Quick refresh and background color

I have experimented with the 4.2 inch e-ink display from waveshare, and the last days I have tried to make quick refresh work. I have observed a number of deficiencies in this library, some of which I do not know how to fix:

  • Newer 4.2" B/W displays seem to require different LUTs for quick refresh.

    As indicated by a comment below Ben Krasnow's blog post on quick refresh on this display, there are two versions of the display. I copied the LUTs from the example code for the greyscale Good Display display (does that mean that my B/W display properly supports greyscale? Yay!) and those result in proper black/white pixels, whereas the LUTs in this library currently only result in grey pixels.

    Link to the example code: http://www.e-paper-display.com/download_detail/downloadsId=1022.html

    My commit (the old LUTs should probably be accessible though - preferrably not behind a feature gate, but selectable at runtime): mgottschlag@a24bec5

  • I am unsure what the point of the "background color" provided by this library is - the documentation is lacking and I think usage the background color as-is is wrong and unusable.

    My understanding of the background (or "old" frame as called by the documentation is that it allows to choose different LUTs based on what the previous image was. Note that the data is actually required for quick refresh using the LUTs in the example code above, as those completely skip pixels that do not change color!

    Also, using the wrong background data might cause burn-in issues. According to the internet (I think Ben Krasnows youtube video explained something like this), the applied voltage needs to be on average 0 to prevent charging the display, which causes burn-in. I don't understand the format of the LUTs, but if they are not completely balanced (and inofficial quick refresh LUTs likely are not!), then using the same LUT over and over again causes the display to be charged (whereas only applying voltages during black/white and white/black transitions might cause the effects to cancel each other out and also greatly reduces the number of pixel changes).

    At least, the library requires updates to the documentation.

  • The library does not provide a method to upload the "old" ("background") data.

    The official quick refresh LUTs for this display depend on having the old data.

    My take on this issue: mgottschlag@dbd065a

Fail to interact with epd3in7 display

Hello,

I want to use an epd3in7 with a stm32f446 that is mounted on a nucleo dev board. I wrote the following code, that is heavily inspired from https://github.com/stm32-rs/stm32f4xx-hal/blob/master/examples/ist7920-bidi-normal-spi.rs It uses the SPI3 pins of the board instead of SPI1 as advised by waveshare wiki because there is a pin conflict on PA5 between SPI1 and the onboard led.

My code is meant to initialize the EPD on SPI3 and blink, but it does not blink. If I do comment the line initializing the EPD, the board blinks. So I guess that initializing the EPD results in a panic for some reason.

I suspected that my SPI is not working, so my code only blinks if MISO is connected to the GND, and it works: if MISO is connected to 3.3V for example, it does not blink. I tested expecting 0xff, and then it blinks when on 3.3v but not on GND, so I'd say that my SPI is OK.

Since I'm a noob at this kind of game, I'd really appreciate if someone could give me a clue about what's going wrong. I'm sorry if it's a stupid error from me, I fail to spot it.

#![no_std]
#![no_main]

use cortex_m_rt::entry;
use stm32f4xx_hal::{
    pac,
    spi,
    gpio::GpioExt,
    prelude::*,
    timer::Timer,
};
#[allow(unused_imports)]
use panic_halt; // When a panic occurs, stop the microcontroller

use embedded_graphics::{
    mono_font::MonoTextStyleBuilder,
    prelude::*,
    text::{Baseline, Text, TextStyleBuilder},
};

use epd_waveshare::{
    color::*,
    epd3in7::{EPD3in7,Display3in7},
    prelude::*,
};

#[entry]
fn main() -> ! {
    let dp = pac::Peripherals::take().unwrap();
    let cp = cortex_m::peripheral::Peripherals::take().unwrap();

    let gpioa = dp.GPIOA.split();
    let gpiob = dp.GPIOB.split();
    let rcc = dp.RCC.constrain();

    let clocks = rcc.cfgr.freeze();

    let mut led = gpioa.pa5.into_push_pull_output();
    led.set_low();

    // Configure SPI
    // Inspiration: stm32f4xx-hal/examples/ist7920-bidi-normal-spi.rs
    let sck = gpiob.pb3.into_alternate();
    let miso = gpiob.pb4.into_push_pull_output();
    let mosi = gpiob.pb5.into_alternate();

    let dc = gpiob.pb14.into_push_pull_output();
    let rst = gpiob.pb10.into_push_pull_output();
    let cs = gpiob.pb13.into_push_pull_output();

    let mut delay = Timer::syst(cp.SYST, &clocks).delay();

    let mut spi = dp.SPI1.spi(
        (sck, miso, mosi),
        spi::Mode {
            polarity: spi::Polarity::IdleLow,
            phase: spi::Phase::CaptureOnFirstTransition,
        },
        8.MHz(),
        &clocks,
    );

    // Configure the other pins
    let busy = gpioa.pa3.into_input();

    //let mut epd = EPD3in7::new(&mut spi, cs, busy, dc, rst, &mut delay, None).expect("EPD init error"); // UNCOMMENT TO LET THE CODE PANIC
    /*
    let mut display = Display3in7::default();

    let style = MonoTextStyleBuilder::new()
        .font(&embedded_graphics::mono_font::ascii::FONT_6X10)
        .text_color(Color::White)
        .background_color(Color::Black)
        .build();
    let text_style = TextStyleBuilder::new().baseline(Baseline::Top).build();
    let _ = Text::with_text_style("Hello Rust!", Point::new(5, 50), style, text_style).draw(&mut display);
        
    // Transfer the frame data to the epd and display it
    epd.update_and_display_frame( & mut spi, & display.buffer(), &mut delay).expect("Error while drawing");
*/
    loop {
        let mut read = [0x55];
        spi.transfer(&mut read).unwrap();
        if read[0] == 0xff {
            led.set_high();
            delay.delay_ms(200_u16);
            led.set_low();
            delay.delay_ms(50_u16);
        }
    }
}

Cannot implement update_partial_frame

Other methods take a delay parameter, but not this one, this prevents me from implementing update_partial_frame from the WaveshareDisplay trait properly, because i need to wait for the idle pin

Changing this means changing a trait, would you accept a PR to change it ?

Not all color displays use `TriDisplay`

TriDisplay was added in #76, but only epd2in13bc was updated to use it. None of the other colored displays use it, except for epd1in83b which was added afterwards and used it from the start.
I think the other displays should probably use it too; here's the full list:

  • epd1in54b
  • epd1in54c
  • epd2in13bc
  • epd2in7b
  • epd2in9bc
  • epd5in83b_v2

Would you be happy for me to implement this?

Could code be more generic ?

Firt let me point that most waveshare epd are identical as goodisplay products.
Goodisplay better document their product and include the integrated circuit name in de datasheet.
This way we can know which epd has the exact same IC as which one.

In this case, I think we should just write generic driver for those ICs and instanciate them with some specific values for each epd we want to support. This would greatly reduce code size and make bug fix propagate to similar epd that share the same code.

For example 7in5b shares the exact same datasheet as 5in83b and as UC8179c IC at goodisplay. Only some data change.
I'd like to make a

// generic impl
struct UC8179c<S: UC8179cSettings> { ... }
impl<S> UC8179c<S> { ...ย }

// specific EPD
impl UC8179cSettings for Epd7in5bSettings { ... }
type Epd7in5b = UC8179c<Epd7in5bSettings>;

where the Setting would just be a bunch of constants

This would also simplify extracting default LUT data (which format is common to a given IC) to play with them

Issues trying to draw embedded graphics image

163 | let bus = Image::new(&ImageRaw::new(include_bytes!("../../icons/Bus.raw"), 30),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait From<()> is not implemented for epd_waveshare::color::Color
|

I guess it's missing some conversions?

It's defined as

impl<'a, C, BO> ImageRaw<'a, C, BO>
where
    C: PixelColor + From<<C as PixelColor>::Raw>,
    BO: ByteOrder,
{

I also tried creating a BinaryColor raw image, but then I cannot draw it on a "Color" display.

would it be possible to standardize into "BinaryColor" from embedded_graphics?, I could be missing lots of things, ... still new to rust.

Epd7in5: index out of bounds on display.clear(TriColor::White)

With epd-waveshare = { git = "https://github.com/caemor/epd-waveshare" } in Cargo.toml

This call to clear() crash with an index out of bounds error

    let mut epd7in5 = Epd7in5::new(&mut spi, cs, busy, dc, rst, &mut delay, None)
        .expect("error");

    let mut display = Display7in5::default();

    display.clear(TriColor::White).ok();

The crash ocures here:

buffer[index] = buffer[index] & mask | (bits >> 8) as u8;

thread 'main' panicked at 'index out of bounds: the len is 48000 but the index is 48000', /cargo/git/checkouts/epd-waveshare-201024d8b8447899/f98c121/src/graphics.rs:353:25
stack backtrace:
   0: rust_begin_unwind
             at /rustc/8460ca823e8367a30dda430efda790588b8c84d3/library/std/src/panicking.rs:575:5
   1: core::panicking::panic_fmt
             at /rustc/8460ca823e8367a30dda430efda790588b8c84d3/library/core/src/panicking.rs:64:14
   2: core::panicking::panic_bounds_check
             at /rustc/8460ca823e8367a30dda430efda790588b8c84d3/library/core/src/panicking.rs:159:5
   3: epd_waveshare::graphics::set_pixel
             at /cargo/git/checkouts/epd-waveshare-201024d8b8447899/f98c121/src/graphics.rs:353:25
   4: epd_waveshare::graphics::Display<_,_,_,_,COLOR>::set_pixel
             at /cargo/git/checkouts/epd-waveshare-201024d8b8447899/f98c121/src/graphics.rs:161:9
   5: <epd_waveshare::graphics::Display<_,_,_,_,COLOR> as embedded_graphics_core::draw_target::DrawTarget>::draw_iter
             at /cargo/git/checkouts/epd-waveshare-201024d8b8447899/f98c121/src/graphics.rs:110:13
   6: embedded_graphics_core::draw_target::DrawTarget::fill_contiguous
             at /cargo/registry/src/github.com-1ecc6299db9ec823/embedded-graphics-core-0.3.3/src/draw_target/mod.rs:392:9
   7: embedded_graphics_core::draw_target::DrawTarget::fill_solid
             at /cargo/registry/src/github.com-1ecc6299db9ec823/embedded-graphics-core-0.3.3/src/draw_target/mod.rs:408:9
   8: embedded_graphics_core::draw_target::DrawTarget::clear
             at /cargo/registry/src/github.com-1ecc6299db9ec823/embedded-graphics-core-0.3.3/src/draw_target/mod.rs:423:9

Release new version

I created a new project copied the epd4in2 example and ran into the following error:

help: trait impl with same name found
   --> /home/marcel/.cargo/registry/src/github.com-1ecc6299db9ec823/epd-waveshare-0.3.2/src/color.rs:57:1
    |
57  | impl PixelColor for Color {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: perhaps two different versions of crate `embedded_graphics` are being used?
    = note: required by `embedded_graphics::style::text_style::TextStyleBuilder::<C, F>::new`
    = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)

Turned out master depends on a later version of the embedded-graphics crate.

thermometer is ๐Ÿ“ฆ v0.1.0 via ๐Ÿฆ€ v1.42.0 
โฏ cargo tree -i -p embedded-graphics:0.6.1
embedded-graphics v0.6.1
โ””โ”€โ”€ thermometer v0.1.0 (/home/marcel/github/thermometer)

thermometer is ๐Ÿ“ฆ v0.1.0 via ๐Ÿฆ€ v1.42.0 
โฏ cargo tree -i -p embedded-graphics:0.4.9
embedded-graphics v0.4.9
โ””โ”€โ”€ epd-waveshare v0.3.2
    โ””โ”€โ”€ thermometer v0.1.0 (/home/marcel/github/thermometer)

Temporary workaround is basically:

embedded-graphics = "0.6.1"
epd-waveshare = { git = "https://github.com/caemor/epd-waveshare.git", rev = "79c2524c1d0980cad6e5033e7fc529a3033da774"}

DisplayInterface::data should write one byte at a time

I've been trying to get the Waveshare 2.7" grayscale display working and I've been having some major issues, but I think the primary blocker is that DisplayInterface::data (and write) tries to write all the data at once rather than byte by byte, which breaks on some devices.

See https://github.com/waveshare/e-Paper/blob/2a10334edcdd4e1c75eb74c7be3b6601614bef72/RaspberryPi_JetsonNano/python/lib/waveshare_epd/epd2in7.py#L164-L174 for the implementation on the 2.7". Note that the 2.7" chromatic display also uses the same code: https://github.com/waveshare/e-Paper/blob/2a10334edcdd4e1c75eb74c7be3b6601614bef72/RaspberryPi_JetsonNano/python/lib/waveshare_epd/epd2in7b.py#L111-L121.

There are some devices which seem to use a separate method to write a chunk of data at a time, but they seem to be the exception rather than the norm (https://github.com/waveshare/e-Paper/blob/2f1eeee9f5baa1753839cb1917f4e75b0c612620/RaspberryPi_JetsonNano/python/lib/waveshare_epd/epd7in5.py#L70-L74).

In my hacked up version, changing data to send bytes one at a time fixed the epd2in7. One of the issues I was seeing was that commands would hang when waiting for them to complete, in other cases it was displaying garbage, so it might fix #70, #68, and maybe others.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.