rust-embedded-community / ssd1306

SSD1306 OLED driver
Apache License 2.0
286 stars 68 forks source link

Print text seems to not work with stm32l432kc #100

Closed lucazulian closed 4 years ago

lucazulian commented 4 years ago

Description of the problem/feature request/other

I was trying to print some text out but with the code below I not able to see anything into the display. I've tried to change che I2C pin, frequency etc; I didn't spend much time debugging because I don't know if the problem is related to the stm32l432kc implementation, with the ssd1306 or not. How can I test this issue?

Test case (if applicable)

//! Reads data from a gyuvl53l0x sensor

#![no_main]
#![no_std]

extern crate cortex_m;
extern crate cortex_m_rt as rt;
extern crate stm32l4xx_hal as hal;
extern crate ssd1306;

use cortex_m_semihosting::hprintln;
use crate::hal::prelude::*;
use crate::hal::stm32l4::stm32l4x2;
use crate::hal::i2c::I2c;
use crate::rt::entry;
use core::panic::PanicInfo;

use ssd1306::{mode::GraphicsMode, Builder, interface::I2cInterface};

use embedded_graphics::pixelcolor::BinaryColor;
use embedded_graphics::fonts::{Font6x8, Font12x16};
use embedded_graphics::prelude::*;
use embedded_graphics::Drawing;

#[entry]
fn main() -> ! {
    hprintln!("Hello, world!").unwrap();

    let dp = stm32l4x2::Peripherals::take().unwrap();

    let mut flash = dp.FLASH.constrain();
    let mut rcc = dp.RCC.constrain();

    let clocks = rcc.cfgr.freeze(&mut flash.acr);

    let mut gpioa = dp.GPIOA.split(&mut rcc.ahb2);

    let mut gpiob = dp.GPIOB.split(&mut rcc.ahb2);
    let mut led = gpiob.pb3.into_push_pull_output(&mut gpiob.moder, &mut gpiob.otyper);

    let mut scl = gpioa
        .pa9
        .into_open_drain_output(&mut gpioa.moder, &mut gpioa.otyper);
    scl.internal_pull_up(&mut gpioa.pupdr, true);
    let scl = scl.into_af4(&mut gpioa.moder, &mut gpioa.afrh);

    let mut sda = gpioa
        .pa10
        .into_open_drain_output(&mut gpioa.moder, &mut gpioa.otyper);
    sda.internal_pull_up(&mut gpioa.pupdr, true);
    let sda = sda.into_af4(&mut gpioa.moder, &mut gpioa.afrh);

    hprintln!("Start configuring I2C").unwrap();

    let i2c = I2c::i2c1(dp.I2C1, (scl, sda), 400.khz(), clocks, &mut rcc.apb1r1);

    hprintln!("Start configuring SSD1306").unwrap();

    let mut disp: GraphicsMode<_> = Builder::new().connect_i2c(i2c).into();

    disp.init().unwrap();
    disp.flush().unwrap();

    let (a, b) = disp.get_dimensions();

    hprintln!("{:#?}", a).unwrap();
    hprintln!("{:#?}", b).unwrap();

    disp.draw(
        Font12x16::render_str("rust")
        .stroke(Some(BinaryColor::On))
        .translate(Point::new(10, 10))
            .into_iter(),
    );

    hprintln!("b").unwrap();
    disp.flush().unwrap();

    led.set_high().unwrap();
    hprintln!("c").unwrap();

    loop {}
}

#[panic_handler]
#[no_mangle]
pub fn panic(_info: &PanicInfo) -> ! {
    loop{}
}

test case dependencies

[package]
authors = ["Luca Zulian <lucagiuggia@gmail.com>"]
edition = "2018"
readme = "README.md"
name = "robot"
version = "0.1.1"

[dependencies]
cortex-m = "0.6.1"
cortex-m-rtfm = "0.4.3"
panic-halt = "0.2.0"
alloc-cortex-m = "0.3.5"
embedded-hal = "0.2.3"
generic-array = "0.13.2"
nb = "0.1.0"
cortex-m-semihosting = "0.3.5"

gyuvl53l0x = "0.1.3"
ssd1306 = "0.3.0-alpha.2"
embedded-graphics = "0.6.0-alpha.2"

[dependencies.stm32l4xx-hal]
git = "https://github.com/stm32-rs/stm32l4xx-hal"
branch = "master"
features = ["stm32l4x2", "rt"]

[dependencies.cortex-m-rt]
version = "0.6.10"
features = ["device"]

[dependencies.cast]
default-features = false
version = "0.2.2"

[dependencies.safe-transmute]
version =  "0.10.1"
default-features = false

[[bin]]
name = "robot"
test = false
bench = false

[profile.release]
codegen-units = 1 # better optimizations
debug = false # symbols are nice and they don't increase the size on Flash
lto = true # better optimizations
panic = "abort"
opt-level = 's'

[profile.dev]
panic = "abort"

Can someone explain me how to "solve" or debug this kind of issue?

jamwaffles commented 4 years ago

Thanks for the report! This is going to be difficult for me to reproduce as I don't have an STM32L4xx board lying around. If you have another SSD1306 and dev board to test with, can you try different combinations of those? That will rule out whether the hardware is broken in some way or not. In your example above, do all the htprintln!()s print out or does it get stuck/crash somewhere?

My only other suggestion right now would be to disable the pullups set by scl.internal_pull_up()/sda.internal_pull_up().

jamwaffles commented 4 years ago

This is going to be difficult for me to reproduce as I don't have an STM32L4xx board lying around.

Turns out I have an STM32F411 board somewhere. I'll dig that out in the next couple of days and see if I can repro/find a fix.

jamwaffles commented 4 years ago

Managed to reproduce your issue on my Nucleo STM32F411 board. After a bunch of issue reading I found stm32-rs/stm32f4xx-hal#99 which fixed the SSD1306 411 example for me. I've opened stm32-rs/stm32f4xx-hal#120 to fix the examples in that repo.

So that's that mystery solved. Unfortunately I still don't know why your L411 board isn't working. Maybe open an issue in stm32-rs/stm32l4xx-hal repo? I'm pretty sure it's not the SSD1306 driver. There seem to be quite a few bugs around I2C and the various STM32x4xx devices floating around :confused:

jamwaffles commented 4 years ago

As mentioned in stm32-rs/stm32f4xx-hal#99 and fixed in stm32-rs/stm32f4xx-hal#120, adding .set_open_drain() to SCL and SDA fixes the problem for me on an F446 Nucleo as well as the 411 I tested a while back. I also had to change from 400KHz to 100KHz to get it working. Can you try those changes and let me know if it works?

gl4eqen commented 4 years ago

Reproduced issue on STM32F407VET6. Thanks to @jamwaffles. It appears that lacking knowledge might get painful.

let peripherals = stm32f4::stm32f407::Peripherals::take().unwrap();
let clocks = peripherals.RCC.constrain().cfgr.freeze();

// I2C
let gpiob = peripherals.GPIOB.split();
let (scl, sda) = (gpiob.pb10.into_open_drain_output().into_alternate_af4(), gpiob.pb11.into_open_drain_output().into_alternate_af4());
let i2c = I2c::i2c2(
    peripherals.I2C2,
    (scl, sda),
    500.khz(),
    clocks,
);

Solves an issue. These pins must be in open drain configuration. Otherwise, device will respond with NACKs.