almindor / mipidsi

MIPI Display Serial Interface unified driver
MIT License
108 stars 46 forks source link

Does not work st7789 on esp32 #23

Closed nathansamson closed 1 year ago

nathansamson commented 1 year ago

Logging this as a new bug (although in a way I suspect it might be my own fault). I apolagize in advance if I am misisng some small thing, and this is more a request for help than a bug report

I do have an ESP32 with the st7789 attached to it. Cirtcuit configuration can be found here: https://raw.githubusercontent.com/Fri3dCamp/badge-2020/master/media/Badge_Block.png

Some (setup) example code with Arduino can be found here https://github.com/Fri3dCamp/Badge2020_arduino/blob/main/Badge2020_TFT.h / https://github.com/Fri3dCamp/Badge2020_arduino This code example works (just as sanity check that my hardware is working)

I am pretty sure my pin config is correct (5 for CS, 33 for DC and 26 for RST), as configured in example code from before. (Note 26 does not appear on the schema, maybe it does not have RST, but I tried it with st7789_without_rst as well.., also in working arduino code it has been set as wel

In all cases I just get a black screen and I am not sure why as I expect a cleaned red screen I notice with this I have to configure my own SPI config which is somehow "magically"? handled when using Arduino/Adadruit library so maybe I am doing something wrong here... (I took inspiration from https://github.com/mutantbob/lcd-esp32)

  # Tried both MODE_3 and MODE_0
    let config = <esp_idf_hal::spi::config::Config as Default>::default().data_mode(embedded_hal::spi::MODE_3);
    let spi = esp_idf_hal::spi::Master::<esp_idf_hal::spi::SPI2, _, _, _, esp_idf_hal::gpio::Gpio23<esp_idf_hal::gpio::Unknown>>::new(
        peripherals.spi2,
        esp_idf_hal::spi::Pins {
            sclk: peripherals.pins.gpio18,
            sdo: peripherals.pins.gpio19,
            sdi: Some(peripherals.pins.gpio23),
            cs: None,
        },
        config,
    )
    .unwrap();
    let lcd_dc = peripherals.pins.gpio33.into_output().unwrap();
    let lcd_rst = peripherals.pins.gpio26.into_output().unwrap();
    let lcd_cs = peripherals.pins.gpio5.into_output().unwrap();
    let mut led_bl = peripherals.pins.gpio12.into_output().unwrap();
    led_bl.set_high();
    let di = display_interface_spi::SPIInterface::new(spi, lcd_dc, lcd_cs);
    println!("SPI CONFIG DONE");

    let mut lcd = mipidsi::Display::st7789(di, lcd_rst);
    let mut delay = esp_idf_hal::delay::Ets;
    println!("INIT S");

    lcd.init(
        &mut delay,
        mipidsi::DisplayOptions {
            orientation: mipidsi::Orientation::PortraitInverted(false),
            invert_vertical_refresh: false,
            color_order: Default::default(),
            invert_horizontal_refresh: false,
        },
    ).unwrap();

    println!("INITED");

    lcd.clear(Rgb565::RED);
    println!("CLEAR");

   # I am joining on another thread here to make sure my program does not exit
almindor commented 1 year ago

What is your SPI speed setting (frequency) in both C and Rust code? That's the one thing I don't see mentioned here. It's possible you're running it at too high of a speed. The ST7789 can do up to 60Mhz at times AFAICS but it gets flakey there, depending on the board you use tho.

If not that we could try comparing the init and if you have a logical analyzer capturing the SPI output to see if there's a logical or even a SPI level problem.

Also if you change the RED color to something else, say GREEN does it change the outcome in any way?

nathansamson commented 1 year ago

"What is your SPI speed setting (frequency) in both C and Rust code?"

C code => I have no idea, in my userland code I am not setting SPI settings, this seems all handled by Adafruit library (and even in there I could not find anything really)

Rust code => I stayed with defaults, so I dont specifically set anything.

At some point I tried "let config = ::default().baudrate(24.MHz().into());" but that did not work either...

Note the example rust application esp32 https://github.com/ivmarkov/rust-esp32-std-demo which uses the st7789 driver also doesn't work for .... It surely looks maybe I am just using wrong pins or something (or some other bad configuration, or both the st7789 driver and this driver have same bug)

Ill try a few more things as well, but if anyone has an idea where to look please let me know

nathansamson commented 1 year ago

Okay I finally found something

Look in https://gist.github.com/nathansamson/8ff4efbcd11043bcfda6a3e7cf2d01ea for details

There are 3 files in there

So the breaktrough since previous time was that I was usingt he wrong SPI (2 vs 3) and my pins where out of order...

So now I know my config finally works I think this should fall under bug as with same config st7789 library works but this one doesn't (although it claims it should).

Funliy enough it does not seem to be exactly like https://github.com/almindor/mipidsi/issues/22 there using MODE_3 solved the problem, in my case MODE3 with mipidsi gives a blank screen, and with MODE0 a grayish screen (but certainly not the blue with 2 squares as I expect it)...

almindor commented 1 year ago

Okay I finally found something

Look in https://gist.github.com/nathansamson/8ff4efbcd11043bcfda6a3e7cf2d01ea for details

There are 3 files in there

* Cargo.toml (this is for the st7789 version but can easily be modified by swapping dependencies for mipidsi version)

* mipidsi.rs  this version does NOT work, it shows some greyish background on the screen but nothing more

* st7789.rs It differs only to the previous version how it initializes the lcd, inthis case via st7789. All drawing or SPI operations are the same. This WORKS (displays blue background with 2 squares, green with a red border, as expected)

So the breaktrough since previous time was that I was usingt he wrong SPI (2 vs 3) and my pins where out of order...

So now I know my config finally works I think this should fall under bug as with same config st7789 library works but this one doesn't (although it claims it should).

Funliy enough it does not seem to be exactly like #22 there using MODE_3 solved the problem, in my case MODE3 with mipidsi gives a blank screen, and with MODE0 a grayish screen (but certainly not the blue with 2 squares as I expect it)...

Ok so if I understand correctly, using the "proper" SPI instance works with the ST7789 driver, but still fails with the MipiDSI one.

When it comes to ST7789, which MODE works for you? Can you try lowering your SPI clock to something super slow like 100khz (you'll see individual pixels being pushed, should it work out)?

AFAICS the only difference between the inits of those two drivers (I wrote both of them :D) is the MADCL/Rgb-Bgr flip (if using defaults).

nathansamson commented 1 year ago

Normal Hz (32Mhz)

ST7789 driver

mipidsi driver

Slow Hz (20000.Hz().)

ST7789 driver

mipidsi driver

Recap of initialization (st7789)

    let mut lcd = st7789::ST7789::new(di, lcd_rst, 240, 240);
        lcd.set_orientation(st7789::Orientation::Portrait).unwrap();

        let mut delay = esp_idf_hal::delay::Ets;
        lcd.init(&mut delay).unwrap();

initialization of mdpsi, note the settings that I kind of guessed but for me should worst case result in inverted image and/or wrong colors

let mut lcd = mipidsi::Display::st7789(di, lcd_rst);
    let mut delay = esp_idf_hal::delay::Ets;
    println!("INIT S");

    lcd.init(
        &mut delay,
        mipidsi::DisplayOptions {
            orientation: mipidsi::Orientation::PortraitInverted(false),
            invert_vertical_refresh: false,
            color_order: Default::default(),
            invert_horizontal_refresh: false,
        },
    ).unwrap();
almindor commented 1 year ago

Could you try st7789@v0.7.0 as well? I just want to make sure it still works.

This is really perplexing, the only init difference AFAICS is that mipidsi has a "dynamic" MADCTL based on config (e.g. orientation, color swaps etc.) and "inverts" the RGB by default (which might or might not be needed, it's another odd point).

I'm comparing this to this The only diffs I can see:

  1. let madctl = options.madctl() ^ 0b0000_1000; line which should at worst confuse the colors.
  2. hard_reset being used in all cases with ST7789 while it's a union with sw reset on mipidsi (should be correct that way)
  3. Longer final delay after DISPON in mipidsi

If this is an init issue (without any kind of odd timing or other side-effect problem) then changing these in the mipidsi driver to match should make things work. Everything else is "generic" code that is the same.

nathansamson commented 1 year ago

I can confirm st7789 v0.7.0 works too

If you prepare a branch with the fixes to match st7789 I am happy to try it out to see if that one works and if indeed thats the cause... If you don't have tine for that I might try that later (might only be in weekend)

almindor commented 1 year ago

I can confirm st7789 v0.7.0 works too

If you prepare a branch with the fixes to match st7789 I am happy to try it out to see if that one works and if indeed thats the cause... If you don't have tine for that I might try that later (might only be in weekend)

Could you please try with https://github.com/almindor/mipidsi/tree/st7789init ? Use DisplayOptions::default() for the options which should match madctl to 0x0 (same as st7789). This branch unifies everything else with the ST7789 driver, so if it still doesn't work we're probably seeing some deeper issue that might be semi-random.

One other thing that I didn't touch upon is the backlight pin. I suspect you don't use it though.

nathansamson commented 1 year ago

Ill give it a try later

Backlight pin: that shouldn't matter. As far as I understand its hardlinked with a physical switch (although the example arduino code for my board defines pin 12) -- correction: there has been some activity in that repo which fixes that misconception. Note I also see some noise about the RST button, so maybe that also has an impact... Ill check it out later

nathansamson commented 1 year ago

I tried it out.

So couple of things

Once I used the defaults I could see the 2 small rectangles I was drawing. Note the background color stayed grey while it should have been Blue lcd.clear(Rgb565::BLUE)

So to me it seems 'lcd.clear' is not (properly) implemented? And in the 0.2.1 version the color initialization is not "correct" (maybe there is no one correct and it really depends on the version you are getting...)

I am not sure why my original DisplayOptions where incorrect though (I copied them from another example), looks to me worst case it would do drawing in the wrong orientation?

almindor commented 1 year ago

I tried it out.

So couple of things

* The main inprovement came from using "`DisplayOptions::default()`" and not
mipidsi::DisplayOptions {
            orientation: mipidsi::Orientation::PortraitInverted(false),
            invert_vertical_refresh: false,
            color_order: Default::default(),
            invert_horizontal_refresh: false,
        }

Once I used the defaults I could see the 2 small rectangles I was drawing. Note the background color stayed grey while it should have been Blue lcd.clear(Rgb565::BLUE)

* When using the 0.2.1 version with `DisplayOptions::default()` the colors are wrong though. I see a blue outline with a green background for each rectangle while it should be red outline and green background (Red & Green are switched but that does not fully surprise you so it seems)

Yes this is due to the madctl XOR operation I added (wrongly) in mipidsi thinking the ST7789 had the RGB bit wrong for some reason.

So to me it seems 'lcd.clear' is not (properly) implemented? And in the 0.2.1 version the color initialization is not "correct" (maybe there is no one correct and it really depends on the version you are getting...)

I'm not sure why clear doesn't work. It's odd if a rect works, clear should too.

I am not sure why my original DisplayOptions where incorrect though (I copied them from another example), looks to me worst case it would do drawing in the wrong orientation?

Using a different orientation changes the MADCTL register value. I suspect that there either is a bug or that the given setting draws "in the wrong direction" (off display area).

Just to be 100% sure I understand the results here. The background clear doesn't work in either case, but the drawable rect with border is drawn with wrong colors in both the branch and master if you use the default options, with inverted colors in the master branch, correct?

nathansamson commented 1 year ago

Just to be 100% sure I understand the results here. The background clear doesn't work in either case, but the drawable rect with > border is drawn with wrong colors in both the branch and master if you use the default options, with inverted colors in the master > branch, correct?

0.2.1 has wrong colors, st7789init branch has correct colors. (Both using default drawing options) Neither of them have a full size background (created with "clear")

almindor commented 1 year ago

Just to be 100% sure I understand the results here. The background clear doesn't work in either case, but the drawable rect with > border is drawn with wrong colors in both the branch and master if you use the default options, with inverted colors in the master > branch, correct?

0.2.1 has wrong colors, st7789init branch has correct colors. (Both using default drawing options) Neither of them have a full size background (created with "clear")

Thanks for all the testing. Could you do one more thing please? Add a delay after your last render, and then call clear again to see if that works. I want to exclude "timing" issues with the clear call.

nathansamson commented 1 year ago

No that doesnt work either... So I am initting, clearing (which doesnt do much), drawing 2 rectangles, sleeping 2 seconds, clearing again and still 2 rectangles show

Note using fill_solid works (and rectangle of 240x240)

Note: fill_solid will basically do a set_pixels(0, 0, 240, 240, array of 240 * 240) while clear will do a set_pixels(0, 0, 240, 320, array of 240 * 320) (or set_prixes(0, 0, 320, 240, array of 240 * 320)

and maybe thats the problem that there is problem with set_pixels that its going out of boumds (because wrong orientation)


Yes thats it , when I say that its in Landscape mode clearing works. Note that for me this feels the wrong orientation (my small rectangles are now oriented differently and I feel incorrectly)

My best guess is that clear should be independent from the orientation I want things to be in??? Which in a way makes sense since the orientation is something that is not hardware bound/set (I think), so regardless of how I see my display the clearing should happen the same way?

almindor commented 1 year ago

No that doesnt work either... So I am initting, clearing (which doesnt do much), drawing 2 rectangles, sleeping 2 seconds, clearing again and still 2 rectangles show

Note using fill_solid works (and rectangle of 240x240)

Note: fill_solid will basically do a set_pixels(0, 0, 240, 240, array of 240 * 240) while clear will do a set_pixels(0, 0, 240, 320, array of 240 * 320) (or set_prixes(0, 0, 320, 240, array of 240 * 320)

and maybe thats the problem that there is problem with set_pixels that its going out of boumds (because wrong orientation)

Yes thats it , when I say that its in Landscape mode clearing works. Note that for me this feels the wrong orientation (my small rectangles are now oriented differently and I feel incorrectly)

My best guess is that clear should be independent from the orientation I want things to be in??? Which in a way makes sense since the orientation is something that is not hardware bound/set (I think), so regardless of how I see my display the clearing should happen the same way?

I think you're right. I'll have to go over the orientation MADCTL values vs clear to see where the actual problem lies. I won't be able to do anything until after Sep 10 tho since I'm abroad atm.

almindor commented 1 year ago

@nathansamson if you can please check out #32 to see if this still works with those changes.