{solved} Noob need help with RPI Pico and SH1106 Display

Hello,
could someone be so kind an explain a noob how to convert this Parameter from MicroPython Example into Rust Code ?

MicroPython

spi = SPI(0,baudrate=1000000,polarity=1,phase=1,bits=8,firstbit=SPI.MSB,sck=Pin(18),mosi=Pin(19),miso=Pin(16))

Rust

   // Define SPI pins as stated by the website
    let spi_mosi = pins.gpio19.into_function::<FunctionSpi>();
    let spi_miso = pins.gpio16.into_function::<FunctionSpi>();
    let spi_sclk = pins.gpio18.into_function::<FunctionSpi>();
    let spi_dc = pins.gpio8.into_push_pull_output();
    let spi_cs = pins.gpio10.into_push_pull_output();

    // Define SPI bus
    let spi = Spi::<_, _, _, 8>::new(pac.SPI0, (spi_mosi, spi_miso, spi_sclk));



// Initialize SPI bus
    let spi = spi.init(
        &mut pac.RESETS,
        clocks.peripheral_clock.freq(),
        400.kHz(), // Note that 16MHz is quite a high frequency. If there are artifacts or it
        // doesn't work, try lowering the frequency. 10kHZ should for sure work.
        embedded_hal::spi::MODE_0,
        embedded_hal::spi::Polarity:: ,
        embedded_hal::spi::Phase:: ,

    );

for the last argument, Spi::init() takes an Into<FrameFormat> as last argument, and embedded_hal::spi::Mode can be used directly here. so you just pass whatever mode your peripheral is configured. I would guess you want to use MODE_3 (because polarity = 1 and phase = 1);

let spi = spi.init(
    &mut pac.RESETS,
    clocks.peripheral_clock.freq(),
    400.kHz(),
    embedded_hal::spi::MODE_3,
);

note Spi::init() consumes self and returns a different type, so you must bind it to a variable.

thank you...

but did not work .... no output on the display


    // Define SPI pins as stated by the website
    let spi_mosi = pins.gpio19.into_function::<FunctionSpi>();
    let spi_miso = pins.gpio16.into_function::<FunctionSpi>();
    let spi_sclk = pins.gpio18.into_function::<FunctionSpi>();
    let spi_dc = pins.gpio8.into_push_pull_output();
    let spi_cs = pins.gpio10.into_push_pull_output();

    // Define SPI bus
    let spi = Spi::<_, _, _, 8>::new(pac.SPI0, (spi_mosi, spi_miso, spi_sclk));

    // Initialize SPI bus
    let spi = spi.init(
        &mut pac.RESETS,
        clocks.peripheral_clock.freq(),
        400.kHz(),
        embedded_hal::spi::MODE_3,
    );

    let text_style = MonoTextStyleBuilder::new()
        .font(&FONT_6X10)
        .text_color(BinaryColor::On)
        .build();

    // Define the display using the SPI bus
    let mut display: GraphicsMode<_> = Builder::new().connect_spi(spi, spi_dc, spi_cs).into();

    display.init().unwrap();

can you show the full code please? your code didn't draw anything to the display.

@nerditation

can you show the full code please?

yes sure

got this from Slushee / from youtube
try to mod it for my requirements


#![no_std]
#![no_main]

use bsp::entry;
use bsp::hal::{
    clocks::{init_clocks_and_plls, Clock},
    fugit::RateExtU32,
    gpio::FunctionSpi,
    pac,
    sio::Sio,
    spi::Spi,
    watchdog::Watchdog,
};
use rp_pico as bsp;

use embedded_hal::digital::v2::OutputPin;

use sh1106::{prelude::*, Builder};

use embedded_graphics::{
    mono_font::{ascii::FONT_6X10, MonoTextStyleBuilder},
    pixelcolor::BinaryColor,
    prelude::*,
    text::{Baseline, Text},
};

use defmt_rtt as _;
use panic_probe as _;

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

    // External high-speed crystal on the pico board is 12Mhz
    let external_xtal_freq_hz = 12_000_000u32;
    let clocks = init_clocks_and_plls(
        external_xtal_freq_hz,
        pac.XOSC,
        pac.CLOCKS,
        pac.PLL_SYS,
        pac.PLL_USB,
        &mut pac.RESETS,
        &mut watchdog,
    )
    .ok()
    .unwrap();

    let mut delay = cortex_m::delay::Delay::new(core.SYST, clocks.system_clock.freq().to_Hz());

    let pins = bsp::Pins::new(
        pac.IO_BANK0,
        pac.PADS_BANK0,
        sio.gpio_bank0,
        &mut pac.RESETS,
    );

    // Define LED pins as stated by the website
    let mut red_led = pins.gpio5.into_push_pull_output();
    let mut yellow_led = pins.gpio6.into_push_pull_output();
    let mut green_led = pins.gpio7.into_push_pull_output();

    // Define SPI pins as stated by the website
    let spi_mosi = pins.gpio19.into_function::<FunctionSpi>();
    let spi_miso = pins.gpio16.into_function::<FunctionSpi>();
    let spi_sclk = pins.gpio18.into_function::<FunctionSpi>();
    let spi_dc = pins.gpio8.into_push_pull_output();
    let spi_cs = pins.gpio10.into_push_pull_output();

    // Define SPI bus
    let spi = Spi::<_, _, _, 8>::new(pac.SPI0, (spi_mosi, spi_miso, spi_sclk));

    // Initialize SPI bus
    let spi = spi.init(
        &mut pac.RESETS,
        clocks.peripheral_clock.freq(),
        400.kHz(),
        embedded_hal::spi::MODE_3,
    );

    let text_style = MonoTextStyleBuilder::new()
        .font(&FONT_6X10)
        .text_color(BinaryColor::On)
        .build();

    // Define the display using the SPI bus
    let mut display: GraphicsMode<_> = Builder::new().connect_spi(spi, spi_dc, spi_cs).into();

    display.init().unwrap();
    display.flush().unwrap();

    Text::with_baseline("Hello world!", Point::zero(), text_style, Baseline::Top)
        .draw(&mut display)
        .unwrap();

    display.flush().unwrap();

    loop {
        // Turn LEDs on
        red_led.set_high().unwrap();
        delay.delay_ms(500);
        yellow_led.set_high().unwrap();
        delay.delay_ms(500);
        green_led.set_high().unwrap();
        delay.delay_ms(500);

        // Turn LEDs off
        red_led.set_low().unwrap();
        delay.delay_ms(500);
        yellow_led.set_low().unwrap();
        delay.delay_ms(500);
        green_led.set_low().unwrap();
        delay.delay_ms(500);
    }
}

I don't have a sh1106 module to try it out myself, but I don't see any obvious problems in the code. I can only give some general debugging advices.

first of all, make sure the pin numbers are correct.

then, try different baud rates. for example, I noticed your python code uses 1MHz, maybe the display interface has specific timing requirement.

also, some devices didn't implement SPI protocol strictly correct, e.g. I have encountered devices conflates mode 0 and mode 3. you may try different modes.

finally, if you have access to logic analyzer, you can compare the signals generated by the rust code to the ones generated by the python code and figure out what's going on.

Thanks so much for your time!

got this PINS from the developer of the board

DC → GPIO 8
Reset → GPIO 9
CS → GPIO 10
SCK → GPIO 18
MOSI → GPIO 19

At the circuit diagram there is no MISO connection

I tryed 1 MHz did not work

Mode_0 -> Mode_3 tryed.... nothing to display

logic analyzer

try to rent one may 2nd week of new year

this looks suspicious, your code didn't drive the reset pin, could that be the cause?

may be....

could you help me with the code

let spi_rst = pins.gpio9.into_push_pull_output();

But how to setup later in the code ?

I have no experience with that device, but a quick search of the datasheet seems indicates the reset signal is pulled down during initialization, and needs to be pulled up for normal operation. I assume the pin is directly connected so the following code uses push-pull driver mode, if your hardware requires different treatment, feel free to change it (e.g. to pull-up or pull-down mode):

    let spi_dc = pins.gpio8.into_push_pull_output();
    let spi_cs = pins.gpio10.into_push_pull_output();
+   let mut display_reset = pins.gpio9.into_push_pull_output();

...

    // Define the display using the SPI bus
    let mut display: GraphicsMode<_> = Builder::new().connect_spi(spi, spi_dc, spi_cs).into();

+   // reset the device before initialization
+   display_reset.set_low().unwrap();
+   delay.delay_ms(200);
+   display_reset.set_high().unwrap();
    display.init().unwrap();

btw, how did the python code initialize the display? did the driver manages reset or did the user code drive the reset signal?

oh, just checked the sh1106 crate, it turns out the driver can do the reset for you.

+   display.reset(&mut display_reset, &mut delay).unwrap();
    display.init().unwrap();

see

@nerditation

thank you so much!

Display work now !

I can show my gratitude ?

You should see some sort of "mark as solution" button below their comment. If you use that, it'll tell the forum that a comment author solved your problem, which updates the topic name and adds to the stats you see when looking at a person's profile.

thanks

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.