From a04cf2dbb8d2e890405fbf0a1022aaad3015b1e8 Mon Sep 17 00:00:00 2001 From: Christian Cunningham Date: Fri, 26 Aug 2022 17:25:34 -0700 Subject: Modularize --- src/bsp/drivers/uart/console.rs | 112 +++++++++++++++++++++++++++++++++++++ src/bsp/drivers/uart/mod.rs | 119 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 231 insertions(+) create mode 100644 src/bsp/drivers/uart/console.rs create mode 100644 src/bsp/drivers/uart/mod.rs (limited to 'src/bsp/drivers/uart') diff --git a/src/bsp/drivers/uart/console.rs b/src/bsp/drivers/uart/console.rs new file mode 100644 index 0000000..e3ee2f2 --- /dev/null +++ b/src/bsp/drivers/uart/console.rs @@ -0,0 +1,112 @@ +//! # UART Console Definition +use super::*; +use crate::bsp::drivers::gpio::*; +use crate::cpu::*; +use crate::lib::sync::interface::Mutex; +use crate::lib::sync::SpinLock; +use core::fmt; + +/// # 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: SpinLock, +} + +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) { + UART::CR::off(); + GPPUDCLK0::init(); + UART::ICR::clear(); + UART::IBRD::set(9); + UART::FBRD::set(49); + UART::LCRH::enable8(); + UART::IMSC::mask(); + UART::CR::all_on(); + } + + /// # Write `char` to UART + fn write_char(&mut self, ch: char) { + while UART::FR::TXFF::is_set() { + nop(); + } + UART::DR::set(ch); + self.chars_written += 1; + } + + /// # Flush UART + fn flush(&self) { + while UART::FR::BUSY::is_set() { + 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: SpinLock::new(UartInner::new()), + } + } + + /// # Call UART initialization + pub fn init(&self) -> Result<(), &'static str> { + self.inner.lock(|inner| inner.init()); + Ok(()) + } +} + +impl crate::lib::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 crate::lib::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 crate::lib::console::interface::All for Uart {} diff --git a/src/bsp/drivers/uart/mod.rs b/src/bsp/drivers/uart/mod.rs new file mode 100644 index 0000000..ad11e12 --- /dev/null +++ b/src/bsp/drivers/uart/mod.rs @@ -0,0 +1,119 @@ +/// # UART Registers +pub mod UART { + /// # Flag Register + pub mod FR { + pub mod BUSY { + const MASK: u32 = 1 << 3; + pub fn is_set() -> bool { + super::read() & MASK != 0 + } + + pub fn is_clear() -> bool { + !is_set() + } + } + pub mod TXFF { + const MASK: u32 = 1 << 5; + pub fn is_set() -> bool { + super::read() & MASK != 0 + } + + pub fn is_clear() -> bool { + !is_set() + } + } + const ADDR: u32 = 0x3F201018; + //pub const TXFF: u32 = 1 << 5; + pub fn read() -> u32 { + use crate::cpu::load32; + load32(ADDR) + } + } + /// # Data Register + pub mod DR { + const ADDR: u32 = 0x3F201000; + pub fn set(c: char) { + use crate::cpu::store32; + store32(ADDR, c as u32); + } + } + /// # Control Register + pub mod CR { + const ADDR: u32 = 0x3F201030; + const UART_ENABLE: u32 = 1 << 0; + const TX_ENABLE: u32 = 1 << 8; + const RX_ENABLE: u32 = 1 << 9; + pub fn set(v: u32) { + use crate::cpu::store32; + store32(ADDR, v); + } + pub fn off() { + set(0); + } + pub fn all_on() { + set(UART_ENABLE + TX_ENABLE + RX_ENABLE) + } + } + /// # Integer Baud Rate + pub mod IBRD { + const ADDR: u32 = 0x3F201024; + pub fn set(v: u32) { + use crate::cpu::store32; + store32(ADDR, v); + } + } + /// # Fractional Baud Rate + pub mod FBRD { + const ADDR: u32 = 0x3F201028; + pub fn set(v: u32) { + use crate::cpu::store32; + store32(ADDR, v); + } + } + /// # Interrupt Control Register + pub mod ICR { + const ADDR: u32 = 0x3F201044; + pub fn set(v: u32) { + use crate::cpu::store32; + store32(ADDR, v); + } + pub fn clear() { + set(0x7FF); + } + } + /// # Line Control Register + pub mod LCRH { + const ADDR: u32 = 0x3F20102C; + const FIFO_ENABLE: u32 = 1 << 4; + const FIVE_BIT: u32 = 0b00 << 5; + const SIX_BIT: u32 = 0b01 << 5; + const SEVEN_BIT: u32 = 0b10 << 5; + const EIGHT_BIT: u32 = 0b11 << 5; + pub fn set(v: u32) { + use crate::cpu::store32; + store32(ADDR, v); + } + pub fn enable8() { + set(FIFO_ENABLE + EIGHT_BIT); + } + } + /// # Interrupt Mask Set/ Clear Register + pub mod IMSC { + const ADDR: u32 = 0x3F201038; + const MASK: u32 = + (1 << 1) | (1 << 4) | (1 << 5) | (1 << 6) | (1 << 7) | (1 << 8) | (1 << 9) | (1 << 10); + pub fn set(v: u32) { + use crate::cpu::store32; + store32(ADDR, v); + } + pub fn mask() { + set(MASK); + } + } +} + +mod console; +pub use console::*; + +/// # Public reference to console. +pub static UART_WRITER: Uart = Uart::new(); -- cgit v1.2.1