diff options
| author | Christian Cunningham <cc@localhost> | 2022-08-26 17:25:34 -0700 | 
|---|---|---|
| committer | Christian Cunningham <cc@localhost> | 2022-08-26 17:25:34 -0700 | 
| commit | a04cf2dbb8d2e890405fbf0a1022aaad3015b1e8 (patch) | |
| tree | 381892074d13c059d50cb88caa41f8a8722c07ce /src/bsp/drivers/uart | |
| parent | 7f3d7d9ce9818078b6a4616b4c31a28e2868397b (diff) | |
Modularize
Diffstat (limited to 'src/bsp/drivers/uart')
| -rw-r--r-- | src/bsp/drivers/uart/console.rs | 112 | ||||
| -rw-r--r-- | src/bsp/drivers/uart/mod.rs | 119 | 
2 files changed, 231 insertions, 0 deletions
| 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<UartInner>, +} + +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(); | 
