almindor / mipidsi

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

ST7789 display is blank #134

Closed alistair23 closed 1 month ago

alistair23 commented 1 month ago

Hey,

I'm running the latest from master trying to get a ST7789V2 working.

The code I'm using is below. I have hooked a logic analyser up and see a LOT of SPI traffic, but the display is just black. The backlight is working (it's just hard wired to high).

Any hints on how to debug a black screen? I'm a bit lost and there is so much traffic being generated that it's hard to manually verify it's correct.

// Display
const W: i32 = 240;
const H: i32 = 280;

    let mut gpio_dc = Gpio::get_pin(0).unwrap();
    let dc = gpio_dc.make_output().unwrap();

    let di = SPIInterface::new(Spi, dc);

    let mut delay = Delay;
    let mut display = Builder::new(ST7789, di)
        .display_size(W as u16, H as u16)
        .invert_colors(ColorInversion::Inverted)
        .init(&mut delay)
        .unwrap();

    // Text
    let char_w = 10;
    let char_h = 20;
    let text_style = MonoTextStyle::new(&FONT_10X20, Rgb565::WHITE);
    let text = "Hello World ^_^;";
    let mut text_x = W;
    let mut text_y = H / 2;

    // Alternating color
    let colors = [Rgb565::RED, Rgb565::GREEN, Rgb565::BLUE];

    // Clear the display initially
    display.clear(colors[0]).unwrap();

    writeln!(Console::writer(), "Done clear\r").unwrap();

    // Draw text
    let right = Text::new(text, Point::new(text_x, text_y), text_style)
        .draw(&mut display)
        .unwrap();
    text_x = if right.x <= 0 { W } else { text_x - char_w };
rfuest commented 1 month ago

We have recently added a section about the RESET pin to the troubleshooting docs, which might be your problem: https://github.com/almindor/mipidsi/blob/master/docs/TROUBLESHOOTING.md#reset-pin

alistair23 commented 1 month ago

Thanks. The reset pin is held high. I'll try connecting it to the crate.

I'll also try slowing down the SPI speed to see if that helps

rfuest commented 1 month ago

If that doesn't fix the problem: How do you control the CS pin? Your code snippet doesn't show how the SpiDevice is created. It's important that the CS pin is driven high before Builder::init is called. If you use a SpiDevice implementation from the embedded-hal-bus crate this is ensured if you use at least version 0.2.0.

alistair23 commented 1 month ago

The reset pin troubleshooting didn't seem to fix the issue. Neither did slowing down the SPI speed.

The CS pin is controlled as part of the embedded-hal implementation, the CS pin seems to be driven high before Builder::init is called

image

rfuest commented 1 month ago

The communication looks OK at first glance. Did you create the capture before you added the reset pin to a GPIO? Because the 0x01 command is the soft reset command and that should only be sent if reset isn't controlled by this crate.

Judging by the screenshot you are using a Salae logic analyzer. I've attached a Saleae capture file of a successful initialization of a ST7789 display. st7789.zip

alistair23 commented 1 month ago

That was captured before the reset pin was setup as a GPIO.

I am using a Salae. I looked at your capture and it seems pretty similar. I've attached mine if that's helpful. Really the only difference is that mine has a longer delay between the operations

st7789-not-working.zip

rfuest commented 1 month ago

Strange, I don't see any reason why this wouldn't work. Can you test the display with another library/platform to make sure the hardware is OK?

alistair23 commented 1 month ago

I don't really have a different platform to try unfortunately

rfuest commented 1 month ago

I'm slowly running out of ideas. One of the last things I could think of is to try the original init sequence from the Seeedstudio/Waveshare code. Try to replace the init method in https://github.com/almindor/mipidsi/blob/master/mipidsi/src/models/st7789.rs with this:

fn init<RST, DELAY, DI>(
    &mut self,
    dcs: &mut Dcs<DI>,
    delay: &mut DELAY,
    options: &ModelOptions,
    rst: &mut Option<RST>,
) -> Result<SetAddressMode, InitError<RST::Error>>
where
    RST: OutputPin,
    DELAY: DelayNs,
    DI: WriteOnlyDataCommand,
{
    let madctl = SetAddressMode::from(options);

    match rst {
        Some(ref mut rst) => self.hard_reset(rst, delay)?,
        None => dcs.write_command(SoftReset)?,
    }
    delay.delay_us(150_000);

    dcs.write_raw(0x36, &[0x00])?;
    dcs.write_raw(0x3A, &[0x05])?;
    dcs.write_raw(0xB2, &[0x0B, 0x0B, 0x00, 0x33, 0x35])?;
    dcs.write_raw(0xB7, &[0x11])?;
    dcs.write_raw(0xBB, &[0x35])?;
    dcs.write_raw(0xC0, &[0x2C])?;
    dcs.write_raw(0xC2, &[0x01])?;
    dcs.write_raw(0xC3, &[0x0D])?;
    dcs.write_raw(0xC4, &[0x20])?;
    dcs.write_raw(0xC6, &[0x13])?;
    dcs.write_raw(0xD0, &[0xA4, 0xA1])?;
    dcs.write_raw(0xD6, &[0xA1])?;
    dcs.write_raw(0xE0, &[0xF0, 0x06, 0x0B, 0x0A, 0x09, 0x26, 0x29, 0x33, 0x41, 0x18, 0x16, 0x15, 0x29, 0x2D])?;
    dcs.write_raw(0xE1, &[0xF0, 0x04, 0x08, 0x08, 0x07, 0x03, 0x28, 0x32, 0x40, 0x3B, 0x19, 0x18, 0x2A, 0x2E])?;
    dcs.write_raw(0xE4, &[0x25, 0x00, 0x00])?;
    dcs.write_raw(0x21, &[])?;
    dcs.write_raw(0x11, &[])?;

    delay.delay_us(120_000);

    dcs.write_raw(0x29, &[])?;

    Ok(madctl)
}
alistair23 commented 1 month ago

Thanks for the idea. I tried that, but still no luck.

I also tried changing some of the MCU SPI PIN settings to see if there is something that the ST7789 doesn't like (this does work with other SPI devices), but no luck.

Do you have a good example of a ST7789 that is known to work? I can see if I can test that instead

rfuest commented 1 month ago

I never had any problems with the cheap ST7789 modules you can get on AliExpress or ebay. Just make sure to avoid modules that don't expose the CS pin. This style, which is similar to the module you used, is one which I've tested successfully: http://www.lcdwiki.com/1.69inch_IPS_Module

I'm starting to think that the level shifter on your module might cause the problem. The TXB series level shifters can lead to some weird issues, like in this article that was recently featured on Hackaday: https://joshua0.dreamwidth.org/74833.html.

alistair23 commented 1 month ago

That's an interesting theory. I'll try a different module and see how that goes

alistair23 commented 1 month ago

I tried the same code with the same pin connection of a board without the level shifters and that works. So I'm going to guess it's a level shifter issue