nucleo-l053r8/examples/lcd.rs

172 lines
4.4 KiB
Rust
Executable file

#![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<Output<PushPull>>;
pub type D3PIN = PB3<Output<PushPull>>;
pub type D4PIN = PB5<Output<PushPull>>;
pub type D5PIN = PB4<Output<PushPull>>;
pub type D6PIN = PB10<Output<PushPull>>;
pub type D7PIN = PA8<Output<PushPull>>;
struct LCDHardware<'a> {
d4: &'a mut PB5<Output<PushPull>>,
d5: &'a mut PB4<Output<PushPull>>,
d6: &'a mut PB10<Output<PushPull>>,
d7: &'a mut PA8<Output<PushPull>>,
rs: &'a mut PA10<Output<PushPull>>,
en: &'a mut PB3<Output<PushPull>>,
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<LCDHardware<'a>> {
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;
}
}