Anyone able to point me in the right direction for connecting a SSD1306 display via SPI using the rust_bsp
crate? I’m pretty new to embedded, been learning rust for a couple months now so I’m just not sure if it’s blatant or not if i’m doing something wrong.
I know my connections are right, because I got some c++ code that does some basic display stuff. But i cannot get any output on the display using rust_bsp
. It compiles and flashes to the daisy successfully, just not getting any output on the display. Here’s my code:
#![no_main]
#![no_std]
use panic_semihosting as _;
use cortex_m_rt::{entry, ExceptionFrame, exception};
use daisy_bsp::{
hal::{self, delay::Delay, spi::{NoMiso, MODE_0}, prelude::*, rcc::PllConfigStrategy,},
pac,
};
use ssd1306::{
Ssd1306,
mode::DisplayConfig,
rotation::DisplayRotation,
size::DisplaySize128x64,
};
#[entry]
fn main() -> ! {
let cp = cortex_m::Peripherals::take().unwrap();
let dp = pac::Peripherals::take().unwrap();
let board = daisy_bsp::Board::take().unwrap();
// - power & clocks -------------------------------------------------------
let pwr = dp.PWR.constrain();
let pwrcfg = pwr.vos0(&dp.SYSCFG).freeze();
let ccdr = dp.RCC.constrain()
.use_hse(16.mhz()) // external crystal @ 16 MHz
.pll1_strategy(PllConfigStrategy::Iterative) // pll1 drives system clock
.sys_ck(480.mhz()) // system clock @ 480 MHz
.freeze(pwrcfg, &dp.SYSCFG);
// - pins -----------------------------------------------------------------
let pins = board.split_gpios(
dp.GPIOA.split(ccdr.peripheral.GPIOA),
dp.GPIOB.split(ccdr.peripheral.GPIOB),
dp.GPIOC.split(ccdr.peripheral.GPIOC),
dp.GPIOD.split(ccdr.peripheral.GPIOD),
dp.GPIOE.split(ccdr.peripheral.GPIOE),
dp.GPIOF.split(ccdr.peripheral.GPIOF),
dp.GPIOG.split(ccdr.peripheral.GPIOG)
);
// - SPI1 -----------------------------------------------------------------
let nss = pins.SEED_PIN_7.into_push_pull_output();
let sck = pins.SEED_PIN_8.into_alternate_af5();
let mosi = pins.SEED_PIN_10.into_alternate_af5();
let dc = pins.SEED_PIN_9.into_push_pull_output();
let mut rst = pins.SEED_PIN_30.into_push_pull_output();
let mut delay = Delay::new(cp.SYST, ccdr.clocks);
let spi: hal::spi::Spi<pac::SPI1, hal::spi::Enabled, u8> = dp.SPI1.spi(
(
sck,
NoMiso,
mosi
),
MODE_0,
8.mhz(),
ccdr.peripheral.SPI1, &ccdr.clocks
);
let interface = display_interface_spi::SPIInterface::new(spi, dc, nss);
let mut display = Ssd1306::new(
interface,
DisplaySize128x64,
DisplayRotation::Rotate0,
).into_buffered_graphics_mode();
display.reset(&mut rst, &mut delay).unwrap();
display.init().unwrap();
// Top side
display.set_pixel(0, 0, true);
display.set_pixel(1, 0, true);
display.set_pixel(2, 0, true);
display.set_pixel(3, 0, true);
// Right side
display.set_pixel(3, 0, true);
display.set_pixel(3, 1, true);
display.set_pixel(3, 2, true);
display.set_pixel(3, 3, true);
// Bottom side
display.set_pixel(0, 3, true);
display.set_pixel(1, 3, true);
display.set_pixel(2, 3, true);
display.set_pixel(3, 3, true);
// Left side
display.set_pixel(0, 0, true);
display.set_pixel(0, 1, true);
display.set_pixel(0, 2, true);
display.set_pixel(0, 3, true);
display.flush().unwrap();
loop {}
}
#[exception]
fn HardFault(ef: &ExceptionFrame) -> ! {
panic!("{:#?}", ef);
}
And if it’s any useful insight: So all three versions of the blinky example work, so in one of my attempts of troubleshooting, i tried putting the blinky logic in the same code above, and basically blinky functionality wont work once I initialize the spi
variable here
let spi: hal::spi::Spi<pac::SPI1, hal::spi::Enabled, u8> = dp.SPI1.spi(
(
sck,
NoMiso,
mosi
),
MODE_0,
8.mhz(),
ccdr.peripheral.SPI1, &ccdr.clocks
);
So i’m thinking maybe something is wrong inside the spi
variable?
Idk, been at it all weekend and haven’t figured it out
i have
Data
→ SPI1 MOSI
(seed pin 10)
Clk
→ SPI1 SCK
(seed pin 8)
DC
→ SPI1 MISO
(seed pin 9)
CS
→ SPI1 CS
(seed pin 7)
for RST
i’ve tried 2 approaches
1: connecting the display RST
to daisy pin 30 (which is gpiob PB15 i believe)
2: tried implementing a “NoOutputPin” because the C++ version doesn’t require any rst connections, here’s that implementation
/// Represents an unused output pin.
#[derive(Clone, Copy)]
pub struct NoOutputPin<PinE = ()> {
_m: PhantomData<PinE>,
}
impl<PinE> NoOutputPin<PinE> {
/// Create a new instance of `NoOutputPin`
pub fn new() -> Self {
Self { _m: PhantomData }
}
}
impl<PinE> OutputPin for NoOutputPin<PinE> {
type Error = PinE;
fn set_low(&mut self) -> Result<(), PinE> {
Ok(())
}
fn set_high(&mut self) -> Result<(), PinE> {
Ok(())
}
}