parent
faa5f01f31
commit
517a78d114
@ -1 +1,117 @@
|
|||||||
use super::IO_BASE;
|
use super::IO_BASE;
|
||||||
|
use gpio::{Function, Gpio};
|
||||||
|
use volatile::{ReadOnly, Volatile};
|
||||||
|
|
||||||
|
/// The base address for the `MU` registers.
|
||||||
|
const MU_REG_BASE: usize = IO_BASE + 0x215040;
|
||||||
|
|
||||||
|
/// The `AUXENB` register from page 9 of the BCM2837 documentation.
|
||||||
|
const AUX_ENABLES: *mut Volatile<u8> = (IO_BASE + 0x215004) as *mut Volatile<u8>;
|
||||||
|
|
||||||
|
/// Enum representing bit fields of the `AUX_MU_LSR_REG` register.
|
||||||
|
#[repr(u8)]
|
||||||
|
enum LsrStatus {
|
||||||
|
DataReady = 1,
|
||||||
|
TxAvailable = 1 << 5,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
struct Registers {
|
||||||
|
AUX_MU_IO_REG: Volatile<u8>,
|
||||||
|
__r0: [u8; 3],
|
||||||
|
AUX_MU_IER_REG: Volatile<u8>,
|
||||||
|
__r1: [u8; 3],
|
||||||
|
AUX_MU_IIR_REG: Volatile<u8>,
|
||||||
|
__r2: [u8; 3],
|
||||||
|
AUX_MU_LCR_REG: Volatile<u8>,
|
||||||
|
__r3: [u8; 3],
|
||||||
|
AUX_MU_MCR_REG: Volatile<u8>,
|
||||||
|
__r4: [u8; 3],
|
||||||
|
AUX_MU_LSR_REG: ReadOnly<u8>,
|
||||||
|
__r5: [u8; 3],
|
||||||
|
AUX_MU_MSR_REG: ReadOnly<u8>,
|
||||||
|
__r6: [u8; 3],
|
||||||
|
AUX_MU_SCRATCH: Volatile<u8>,
|
||||||
|
__r7: [u8; 3],
|
||||||
|
AUX_MU_CNTL_REG: Volatile<u8>,
|
||||||
|
__r8: [u8; 3],
|
||||||
|
AUX_MU_STAT_REG: ReadOnly<u32>,
|
||||||
|
AUX_MU_BAUD_REG: Volatile<u16>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The Raspberry Pi's "mini UART".
|
||||||
|
pub struct MiniUart {
|
||||||
|
registers: &'static mut Registers,
|
||||||
|
timeout: Option<u32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MiniUart {
|
||||||
|
/// Initializes the mini UART by enabling it as an auxiliary peripheral,
|
||||||
|
/// setting the data size to 8 bits, setting the BAUD rate to ~115200 (baud
|
||||||
|
/// divider of 270), setting GPIO pins 14 and 15 to alternative function 5
|
||||||
|
/// (TXD1/RDXD1), and finally enabling the UART transmitter and receiver.
|
||||||
|
///
|
||||||
|
/// By default, reads will never time out. To set a read timeout, use
|
||||||
|
/// `set_read_timeout()`.
|
||||||
|
pub fn new() -> MiniUart {
|
||||||
|
let registers = unsafe {
|
||||||
|
// Enable the mini UART as an auxiliary device.
|
||||||
|
(*AUX_ENABLES).write(1);
|
||||||
|
&mut *(MU_REG_BASE as *mut Registers)
|
||||||
|
};
|
||||||
|
|
||||||
|
Gpio::new(14).into_alt(Function::Alt5).set_gpio_pd(0);
|
||||||
|
Gpio::new(15).into_alt(Function::Alt5).set_gpio_pd(0);
|
||||||
|
|
||||||
|
registers.AUX_MU_CNTL_REG.write(0); // Disable auto flow control and disable receiver and transmitter (for now)
|
||||||
|
registers.AUX_MU_IER_REG.write(0); // Disable receive and transmit interrupts
|
||||||
|
registers.AUX_MU_LCR_REG.write(3); // Enable 8 bit mode
|
||||||
|
registers.AUX_MU_MCR_REG.write(0); // Set RTS line to be always high
|
||||||
|
registers.AUX_MU_BAUD_REG.write(270); // Set baud rate to 115200
|
||||||
|
|
||||||
|
registers.AUX_MU_CNTL_REG.write(3); // Finally, enable transmitter and receiver
|
||||||
|
|
||||||
|
MiniUart {
|
||||||
|
registers: registers,
|
||||||
|
timeout: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the read timeout to `milliseconds` milliseconds.
|
||||||
|
pub fn set_read_timeout(&mut self, milliseconds: u32) {
|
||||||
|
self.timeout = Some(milliseconds)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Write the byte `byte`. This method blocks until there is space available
|
||||||
|
/// in the output FIFO.
|
||||||
|
pub fn write_byte(&mut self, byte: u8) {
|
||||||
|
while self.registers.AUX_MU_LSR_REG.read() & (LsrStatus::TxAvailable as u8) == 0 {}
|
||||||
|
self.registers.AUX_MU_IO_REG.write(byte);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns `true` if there is at least one byte ready to be read. If this
|
||||||
|
/// method returns `true`, a subsequent call to `read_byte` is guaranteed to
|
||||||
|
/// return immediately. This method does not block.
|
||||||
|
pub fn has_byte(&self) -> bool {
|
||||||
|
self.registers.AUX_MU_LSR_REG.read() & (LsrStatus::DataReady as u8) != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Blocks until there is a byte ready to read. If a read timeout is set,
|
||||||
|
/// this method blocks for at most that amount of time. Otherwise, this
|
||||||
|
/// method blocks indefinitely until there is a byte to read.
|
||||||
|
///
|
||||||
|
/// Returns `Ok(())` if a byte is ready to read. Returns `Err(())` if the
|
||||||
|
/// timeout expired while waiting for a byte to be ready. If this method
|
||||||
|
/// returns `Ok(())`, a subsequent call to `read_byte` is guaranteed to
|
||||||
|
/// return immediately.
|
||||||
|
pub fn wait_for_byte(&self) -> Result<(), ()> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Reads a byte. Blocks indefinitely until a byte is ready to be read.
|
||||||
|
pub fn read_byte(&mut self) -> u8 {
|
||||||
|
while !self.has_byte() {}
|
||||||
|
self.registers.AUX_MU_IO_REG.read()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in new issue