#![no_main] #![no_std] use chrono::NaiveDateTime; use defmt::info; use heapless::String; use panic_probe as _; use defmt_rtt as _; // global logger use core::fmt::Write; use cortex_m_rt::entry; use hal::{ delay::Delay, gpio::{Output, PushPull, gpioa::*, gpiob::*, gpioc::*}, pac, prelude::*, pwr::PWR, rcc::Config, rtc::{Datelike, Rtc, Timelike}, }; use hd44780_driver::HD44780; #[defmt::panic_handler] fn panic() -> ! { cortex_m::asm::udf() } type Lcd = HD44780< hd44780_driver::bus::FourBitBus< PA9>, PC7>, PB5>, PB4>, PB10>, PA8>, >, >; const UNIXTIME_OF_COMPILATION: i64 = compile_time::unix_local!(); const BUF_SIZE: usize = 20; #[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 pwr = PWR::new(dp.PWR, &mut rcc); let gpioa = dp.GPIOA.split(&mut rcc); let gpiob = dp.GPIOB.split(&mut rcc); let gpioc = dp.GPIOC.split(&mut rcc); // literal D4-D7 ports etc as written on the nucleo board, mapped to the D4-D7 ports of the LCD // controller let d4 = gpiob.pb5.into_push_pull_output(); let d5 = gpiob.pb4.into_push_pull_output(); let d6 = gpiob.pb10.into_push_pull_output(); let d7 = gpioa.pa8.into_push_pull_output(); // clock enable on D9 let en = gpioc.pc7.into_push_pull_output(); // register select on D8, the lib wants that but I'd just put it on ground otherwise let rs = gpioa.pa9.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(); let mut buf: String = String::new(); let mut lcd: Lcd = HD44780::new_4bit(rs, en, d4, d5, d6, d7, &mut delay) .expect("could not init HD44780 driver"); lcd.set_display_mode( hd44780_driver::DisplayMode { cursor_visibility: hd44780_driver::Cursor::Invisible, cursor_blink: hd44780_driver::CursorBlink::Off, display: hd44780_driver::Display::On, }, &mut delay, ) .expect("could not set display properties"); lcd.reset(&mut delay).expect("could not reset the lcd"); let start_time = chrono::DateTime::from_timestamp(UNIXTIME_OF_COMPILATION, 0) .expect("The Compilation time was invalid") .naive_utc(); info!("Compiled time: {}", UNIXTIME_OF_COMPILATION); let mut rtc = Rtc::new(dp.RTC, &mut rcc, &pwr, Some(start_time)).expect("Could not setup RTC"); let mut i: u32 = 0; let mut timestamp = rtc.now(); info!("First RTC time: {}", timestamp.and_utc().timestamp()); loop { led.set_high().unwrap(); timestamp = rtc.now(); display_time( ×tamp, &mut lcd, &mut delay, &mut buf, timestamp.second() == 0 || i == 0, ); led.set_low().unwrap(); delay.delay_us(990_u32); i += 1; } } fn display_time( timestamp: &NaiveDateTime, lcd: &mut Lcd, delay: &mut Delay, buf: &mut String, full_update: bool, ) { if full_update { lcd.clear(delay).expect("could not clear the display"); lcd.set_cursor_pos(0, delay) .expect("could not move cursor to start"); buf.clear(); write!( buf, " {:04}-{:02}-{:02} ", timestamp.year(), timestamp.month(), timestamp.day() ) .expect("could not format text content for display"); lcd.write_str(buf, delay).expect("could not write to LCD"); lcd.set_cursor_pos(40, delay) .expect("could not move cursor to start"); buf.clear(); write!(buf, " (UTC) ",).expect("could not format text content for display"); lcd.write_str(buf, delay).expect("could not write to LCD"); } lcd.set_cursor_pos(20, delay) .expect("could not move cursor to line 2"); buf.clear(); write!( buf, " {:02}:{:02}:{:02} ", timestamp.hour(), timestamp.minute(), timestamp.second() ) .expect("could not format text content for display"); lcd.write_str(buf, delay).expect("could not write to LCD"); }