//! # UART Console Definition use crate::cpu::*; use crate::sync::interface::Mutex; use crate::sync::NullLock; use core::fmt; /// # Data Register const UART0_DR: u32 = 0x3F201000; /// # Flag Register const UART0_FR: u32 = 0x3F201018; /// # Fractional Baud Rate Register const UART0_FBRD: u32 = 0x3F201028; /// # Line Control Register const UART0_LCRH: u32 = 0x3F20102C; /// # Control Register const UART0_CR: u32 = 0x3F201030; /// # Interrupt Mask Set/ Clear Register const UART0_IMSC: u32 = 0x3F201038; /// # Interrupt Control Register const UART0_ICR: u32 = 0x3F201044; /// # Integer Baud Rate Register const UART0_IBRD: u32 = 0x3F201024; /// GPIO Register const GPPUD: u32 = 0x3F200094; /// GPIO Clock 0 Register const GPPUDCLK0: u32 = 0x3F200098; /// # UART Inner Structure /// /// Keeps record of the console statistics. struct UartInner { chars_written: usize, } /// # UART Structure /// /// Wraps the UART writer in a sharable lock. pub struct Uart { inner: NullLock, } impl UartInner { /// # Clear statistics /// /// Create the writer with cleared statistics pub const fn new() -> Self { Self { chars_written: 0 } } /// # Initialize the UART setup /// /// Set baud rate and timings pub fn init(&mut self) { store32(UART0_CR, 0); store32(GPPUD, 0); spin_for_n_cycles(150); store32(GPPUDCLK0, (1 << 14) | (1 << 15)); spin_for_n_cycles(150); store32(GPPUDCLK0, 0); store32(UART0_ICR, 0x7FF); store32(UART0_IBRD, 9); store32(UART0_FBRD, 49); store32(UART0_LCRH, (1 << 4) | (1 << 5) | (1 << 6)); store32( UART0_IMSC, (1 << 1) | (1 << 4) | (1 << 5) | (1 << 6) | (1 << 7) | (1 << 8) | (1 << 9) | (1 << 10), ); store32(UART0_CR, (1 << 0) | (1 << 8) | (1 << 9)); } /// # Write `char` to UART fn write_char(&mut self, ch: char) { while load32(UART0_FR) & 0x20 != 0 { nop(); } store32(UART0_DR, ch as u32); self.chars_written += 1; } /// # Flush UART fn flush(&self) { while load32(UART0_FR) & 0x08 != 0 { nop(); } } } impl fmt::Write for UartInner { /// # Write string to UART console fn write_str(&mut self, s: &str) -> fmt::Result { for c in s.chars() { self.write_char(c); } Ok(()) } } impl Uart { /// # Create sharable UART wrapper pub const fn new() -> Self { Self { inner: NullLock::new(UartInner::new()), } } /// # Call UART initialization pub fn init(&self) -> Result<(), &'static str> { self.inner.lock(|inner| inner.init()); Ok(()) } } impl super::console::interface::Write for Uart { /// # Write `char` to UART fn write_char(&self, c: char) { self.inner.lock(|inner| inner.write_char(c)); } /// # Write formatted string to UART fn write_fmt(&self, args: core::fmt::Arguments) -> fmt::Result { self.inner.lock(|inner| fmt::Write::write_fmt(inner, args)) } /// # Flush UART fn flush(&self) { self.inner.lock(|inner| inner.flush()); } } impl super::console::interface::Statistics for Uart { /// # Get `char` written stats fn chars_written(&self) -> usize { self.inner.lock(|inner| inner.chars_written) } } /// # UART Writer + Stats impl super::console::interface::All for Uart {} /// # Public reference to console. pub static UART_WRITER: Uart = Uart::new();