almindor / mipidsi

MIPI Display Serial Interface unified driver
MIT License
125 stars 48 forks source link

ST7789 display is blank #139

Closed matheusfinatti closed 1 month ago

matheusfinatti commented 5 months ago

Seems to be a recurring issue with this driver. I'm sorry if this has been covered before. I'm an amateur when it comes to embedded and it's my first time doing it.

I have a Pi Pico with a Pimoroni Pico Display 2''. From the example in their repo and the datasheet I managed to figure out the display driver and pin layout, which other issues found here seemed to corroborate.

However, my display is black and the code seems to be stuck at the display init() call. I see the backlight turning on, but I don't see the LED on the board turning on. (Moving the led.set_high() to before the display intialization makes the LED turn on)

I've looked at the troubleshooting, tried to change the SPI mode to 0, 1, 2, 3. Nothing changes.

The display works, if I run the example in the manufacturer repo it runs flawleslly

Thanks in advance.

#![no_std]
#![no_main]

use bsp::entry;
use bsp::hal;
use defmt_rtt as _;
use hal::pac;
use panic_halt as _;

use hal::gpio::*;
use hal::Clock;

use rp_pico as bsp;

// Mipidsi drivers
use mipidsi::*;

// Embedded HAL
use embedded_hal::digital::OutputPin;

// Embedded graphics to draw on the display
use embedded_graphics::draw_target::*;
use embedded_graphics::geometry::*;
use embedded_graphics::pixelcolor::*;
use embedded_graphics::primitives::*;
use embedded_graphics::Drawable;

// Embed the 'Hz' function.
use fugit::RateExtU32;

// Display specs
const WIDTH: i32 = 320;
const HEIGHT: i32 = 240;

#[entry]
fn main() -> ! {
    let mut pac = pac::Peripherals::take().unwrap();
    let mut watchdog = hal::Watchdog::new(pac.WATCHDOG);

    let clocks = hal::clocks::init_clocks_and_plls(
        bsp::XOSC_CRYSTAL_FREQ,
        pac.XOSC,
        pac.CLOCKS,
        pac.PLL_SYS,
        pac.PLL_USB,
        &mut pac.RESETS,
        &mut watchdog,
    )
    .ok()
    .unwrap();

    let mut timer = hal::Timer::new(pac.TIMER, &mut pac.RESETS, &clocks);

    let sio = hal::Sio::new(pac.SIO);
    let pins = hal::gpio::Pins::new(
        pac.IO_BANK0,
        pac.PADS_BANK0,
        sio.gpio_bank0,
        &mut pac.RESETS,
    );

    let mut led_pin = pins.gpio25.into_push_pull_output();

    // Configure SPI pins for display
    let spi_mosi: Pin<_, FunctionSpi, PullNone> = pins.gpio19.reconfigure();
    let spi_sclk: Pin<_, FunctionSpi, PullNone> = pins.gpio18.reconfigure();

    // Init SPI
    let spi = hal::Spi::<_, _, _, 8>::new(pac.SPI0, (spi_mosi, spi_sclk));
    let spi = spi.init(
        &mut pac.RESETS,
        clocks.peripheral_clock.freq(),
        62_500_000.Hz(),
        embedded_hal::spi::MODE_0,
    );

    let dc = pins.gpio16.into_push_pull_output();
    let cs = pins.gpio17.into_push_pull_output();

    // SPI interface
    let spi_device = embedded_hal_bus::spi::ExclusiveDevice::new(spi, cs, timer).unwrap();
    let di = display_interface_spi::SPIInterface::new(spi_device, dc);

    // Reset pin must be set to high.
    let mut rst = pins.gpio22.into_push_pull_output();
    rst.set_high().unwrap();

    // Configure the backlight pin, set to high
    let mut bl = pins.gpio20.into_push_pull_output();
    bl.set_high().unwrap();

    // Initialize the display
    let mut display = Builder::new(models::ST7789, di)
        .reset_pin(rst)
        .display_size(WIDTH as u16, HEIGHT as u16)
        .invert_colors(options::ColorInversion::Inverted)
        .orientation(options::Orientation::default())
        .init(&mut timer)
        .unwrap();

    // Code never reaches here
    led_pin.set_high().unwrap();

    // Clear the display initially
    display.clear(Rgb565::GREEN).unwrap();

    // Draw a rectangle on screen
    let style = embedded_graphics::primitives::PrimitiveStyleBuilder::new()
        .fill_color(Rgb565::GREEN)
        .build();

    embedded_graphics::primitives::Rectangle::new(Point::zero(), display.bounding_box().size)
        .into_styled(style)
        .draw(&mut display)
        .unwrap();

    loop {
        // Do nothing
    }
}
rfuest commented 5 months ago

Seems to be a recurring issue with this driver. I'm sorry if this has been covered before. I'm an amateur when it comes to embedded and it's my first time doing it.

No problem, these issues can be tricky to resolve if you aren't familiar with embedded designs and this crate. There have been quite a few ST7789 related issues lately. I don't know if this is just a sign that this is a popular controller or if we have a problem with our code or at least with incomplete documentation. Every reported issue gives us the opportunity to improve the crate.

However, my display is black and the code seems to be stuck at the display init() call.

That's weird. There is no two way communication between the controller and the display, so that it shouldn't be possible for init to hang, even if the display didn't initialize properly. But my guess that init panics for some reason and causes the panic_abort handler to be called. I would suggest that you switch to another panic handler to see what is causing the issue, like panic-probe which is used in the RP2040 template: https://github.com/rp-rs/rp2040-project-template/blob/main/Cargo.toml

matheusfinatti commented 5 months ago

Thanks, that was very helpful. I could see the error in terminal now.

assertion failed: width + offset_x <= max_width

I checked the ST7789 framebuffer size and is set to 240x320 instead of 320x240, that's why it's failing. Swapping the values around fixed the issue.

Thanks a bunch, spent a good 3-4 hours debugging but without a error message it was hard to point the issue.