//! Driver for the UART. use core::arch::asm; use core::fmt; use crate::traits::console::{Write, Console}; use super::memory_map::uart as mm; pub struct Uart<'a> { initialized: bool, memory_map: &'a mm::UartMemoryMap, } impl<'a> Uart<'a> { // TODO: not sure this should be public outside of bsp. /// Constructor for [`Uart`]. pub const fn new(memory_map: &'a mm::UartMemoryMap) -> Self { Uart { initialized: false, memory_map } } /// Initialise the UART. pub fn init(&mut self) { // TODO: Recover from possible previous test. self.flush(); // Stop UART self.memory_map.cr_uarten.read_and_write(0); // Flush the FIFOs self.memory_map.lcrh_fen.read_and_write(0); // Clear all interrupt self.memory_map.icr.write_without_read(0); // Config UART // 8N1 115_200 bauds. // divbaud = freq/16/baudrate = 48_000_000 / 16 / 115_200 = 26.041666666666668 // => IBRD = 26 // => FBRD = round(0.041666666666668 * 64) = 3 // TODO: why 64? self.memory_map.ibrd.write_without_read(26); self.memory_map.fbrd.write_without_read(3); // Set word len to 8 let lcrh_val = self.memory_map.lcrh_wlen.read_and_write_to_u32(0b11, 0); // Reenable the FIFOs let lcrh_val = self.memory_map.lcrh_fen.read_and_write_to_u32(1, lcrh_val); self.memory_map.lcrh.write_without_read(lcrh_val); let cr_val = self.memory_map.cr_txe.read_and_write_to_u32(1, 0); // TODO: let cr_val = self.memory_map.cr_rxe.read_and_write_to_u32(1, 0); to enable read self.memory_map.cr.write_without_read(cr_val); // Start the UART self.memory_map.cr_uarten.read_and_write(1); self.initialized = true; } /// Test if the UART is busy. fn is_busy(&self) -> bool { self.memory_map.fr_busy.read() != 0 } /// Test if the the TX FIFO is full. fn is_tx_full(&self) -> bool { self.memory_map.fr_txff.read() != 0 } } // Allow the use of uart for fmt::Write::write_fmt. impl fmt::Write for Uart<'_> { fn write_str(&mut self, s: &str) -> fmt::Result { for c in s.chars() { if c == '\n' { Write::write_char(self, '\r'); } Write::write_char(self, c); } Ok(()) } } // TODO: add sync impl Write for Uart<'_> { fn write_char(&self, c: char) { if !self.initialized { //panic!("Cannot write to a non initialized UART"); } while self.is_tx_full() { use super::gpio; let _ = gpio::set_pin_output_state(20, gpio::PinOutputState::High); unsafe { asm!("nop") }; } self.memory_map.dr_data.write_without_read(c as u32); } fn write_fmt(&self, args: fmt::Arguments) -> fmt::Result { // TODO: use syncronisation here let mut new_uart = Uart { initialized: self.initialized, memory_map: self.memory_map}; fmt::Write::write_fmt(&mut new_uart, args) } fn flush(&self) { while self.is_busy() { unsafe { asm!("nop") }; } } } impl Console for Uart<'_> {} static UART: Uart = Uart { initialized: true, memory_map: &mm::UART }; // TODO: use sync pub fn init() { let mut uart = Uart::new(&mm::UART); uart.init(); } // TODO: move? /// Return a reference to the Uart Output. pub fn console() -> &'static dyn Console { &UART }