#![no_main] #![no_std] use defmt::{debug, info}; use hal::{ delay::Delay, gpio::{ Output, PushPull, gpioa::{PA8, PA10}, gpiob::{PB3, PB4, PB5, PB10}, }, }; use panic_probe as _; use defmt_rtt as _; // global logger use core::fmt::Write; use cortex_m_rt::entry; use hal::{pac, prelude::*, rcc::Config}; pub type D2PIN = PA10>; pub type D3PIN = PB3>; pub type D4PIN = PB5>; pub type D5PIN = PB4>; pub type D6PIN = PB10>; pub type D7PIN = PA8>; struct LCDHardware<'a> { d4: &'a mut PB5>, d5: &'a mut PB4>, d6: &'a mut PB10>, d7: &'a mut PA8>, rs: &'a mut PA10>, en: &'a mut PB3>, delay: &'a mut Delay, } impl<'a> LCDHardware<'a> { fn new( d4: &'a mut D4PIN, d5: &'a mut D5PIN, d6: &'a mut D6PIN, d7: &'a mut D7PIN, rs: &'a mut D2PIN, en: &'a mut D3PIN, delay: &'a mut Delay, ) -> lcd::Display> { let hw: LCDHardware<'a> = LCDHardware { d4, d5, d6, d7, rs, en, delay, }; let mut lcd = lcd::Display::new(hw); lcd.init(lcd::FunctionLine::Line2, lcd::FunctionDots::Dots5x8); lcd.display( lcd::DisplayMode::DisplayOn, lcd::DisplayCursor::CursorOn, lcd::DisplayBlink::BlinkOn, ); lcd.entry_mode( lcd::EntryModeDirection::EntryRight, lcd::EntryModeShift::NoShift, ); lcd } } impl lcd::Delay for LCDHardware<'_> { fn delay_us(&mut self, delay_usec: u32) { self.delay.delay_us(delay_usec); } } impl lcd::Hardware for LCDHardware<'_> { fn rs(&mut self, bit: bool) { self.rs .set_state(PinState::from(bit)) .expect("could not set LCD RS") } fn enable(&mut self, bit: bool) { self.en .set_state(PinState::from(bit)) .expect("could not set LCD RS") } fn data(&mut self, data: u8) { let d4 = data & 0b00000001; let d5 = data & 0b00000010; let d6 = data & 0b00000100; let d7 = data & 0b00001000; debug!("Writing data: d4:{}, d5:{}, d6:{}, d7:{}", d4, d5, d6, d7); self.d4 .set_state(PinState::from(d4 > 0)) .expect("could not set LCD D4"); self.d5 .set_state(PinState::from(d5 > 0)) .expect("could not set LCD D5"); self.d6 .set_state(PinState::from(d6 > 0)) .expect("could not set LCD D6"); self.d7 .set_state(PinState::from(d7 > 0)) .expect("could not set LCD D7"); } fn mode(&self) -> lcd::FunctionMode { lcd::FunctionMode::Bit4 } fn can_read(&self) -> bool { false } } #[defmt::panic_handler] fn panic() -> ! { cortex_m::asm::udf() } #[entry] fn main() -> ! { let dp = pac::Peripherals::take().unwrap(); let cp = cortex_m::Peripherals::take().unwrap(); let mut rcc = dp.RCC.freeze(Config::hsi16()); let gpioa = dp.GPIOA.split(&mut rcc); let gpiob = dp.GPIOB.split(&mut rcc); let _gpioc = dp.GPIOC.split(&mut rcc); // clock enable on D2 let mut rs: D2PIN = gpioa.pa10.into_push_pull_output(); // register select on D3, the lib wants that but I'd just put it on ground otherwise let mut en: D3PIN = gpiob.pb3.into_push_pull_output(); let mut d4: D4PIN = gpiob.pb5.into_push_pull_output(); let mut d5: D5PIN = gpiob.pb4.into_push_pull_output(); let mut d6: D6PIN = gpiob.pb10.into_push_pull_output(); let mut d7: D7PIN = gpioa.pa8.into_push_pull_output(); // See https://en.wikipedia.org/wiki/Hitachi_HD44780_LCD_controller#Interface // for the pins of the LCD let mut delay = cp.SYST.delay(rcc.clocks); let mut led = gpioa.pa5.into_push_pull_output(); led.set_high().unwrap(); info!("Writing to LCD..."); let mut lcd = LCDHardware::new( &mut d4, &mut d5, &mut d6, &mut d7, &mut rs, &mut en, &mut delay, ); write!(&mut lcd, "Hello World").expect("could not write to lcd"); info!("Done!"); led.set_low().unwrap(); let mut i = 0; loop { delay.delay_ms(500_u16); i += 1; } }