2019-05-07 06:32:45 +08:00
|
|
|
#![allow(unused)]
|
|
|
|
|
2019-05-07 22:45:31 +08:00
|
|
|
use core::fmt;
|
2019-05-21 07:30:54 +08:00
|
|
|
use volatile_register::RW;
|
2019-05-07 22:45:31 +08:00
|
|
|
|
2019-05-07 23:46:37 +08:00
|
|
|
use crate::regs::*;
|
2019-05-23 23:52:06 +08:00
|
|
|
use crate::slcr;
|
2019-05-07 23:46:37 +08:00
|
|
|
|
2019-05-05 20:56:23 +08:00
|
|
|
mod regs;
|
2019-05-22 07:42:00 +08:00
|
|
|
mod baud_rate_gen;
|
2019-05-07 23:46:37 +08:00
|
|
|
|
2019-05-23 21:50:53 +08:00
|
|
|
/// Determined through experimentation. Actually supposed to be
|
|
|
|
/// 1 GHz (IO PLL) / 0x14 (slcr.UART_CLK_CTRL[DIVISOR]) = 50 MHz.
|
|
|
|
const UART_REF_CLK: u32 = 45_000_000;
|
|
|
|
|
2019-05-05 20:56:23 +08:00
|
|
|
pub struct Uart {
|
2019-05-07 23:46:37 +08:00
|
|
|
regs: &'static mut regs::RegisterBlock,
|
2019-05-05 20:56:23 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Uart {
|
2019-05-23 21:50:53 +08:00
|
|
|
pub fn uart1(baudrate: u32) -> Self {
|
2019-05-23 23:52:06 +08:00
|
|
|
slcr::RegisterBlock::unlocked(|slcr| {
|
|
|
|
slcr.uart_rst_ctrl.reset_uart1();
|
2019-05-21 07:30:54 +08:00
|
|
|
|
|
|
|
// Route UART 1 RxD/TxD Signals to MIO Pins
|
2019-05-23 23:52:06 +08:00
|
|
|
// TX pin
|
|
|
|
slcr.mio_pin_48.write(
|
|
|
|
slcr::MioPin48::zeroed()
|
|
|
|
.l3_sel(0b111)
|
|
|
|
.io_type(0b001)
|
|
|
|
.pullup(true)
|
|
|
|
);
|
|
|
|
// RX pin
|
|
|
|
slcr.mio_pin_49.write(
|
|
|
|
slcr::MioPin49::zeroed()
|
|
|
|
.tri_enable(true)
|
|
|
|
.l3_sel(0b111)
|
|
|
|
.io_type(0b001)
|
|
|
|
.pullup(true)
|
|
|
|
);
|
2019-05-21 07:30:54 +08:00
|
|
|
|
2019-05-23 23:52:06 +08:00
|
|
|
slcr.aper_clk_ctrl.enable_uart1();
|
|
|
|
slcr.uart_clk_ctrl.enable_uart1();
|
2019-05-21 07:30:54 +08:00
|
|
|
});
|
2019-05-07 23:46:37 +08:00
|
|
|
let self_ = Uart {
|
2019-05-21 07:30:54 +08:00
|
|
|
regs: regs::RegisterBlock::uart1(),
|
2019-05-07 23:46:37 +08:00
|
|
|
};
|
2019-05-23 21:50:53 +08:00
|
|
|
self_.configure(baudrate);
|
2019-05-07 23:46:37 +08:00
|
|
|
self_
|
2019-05-05 20:56:23 +08:00
|
|
|
}
|
|
|
|
|
2019-05-07 23:46:37 +08:00
|
|
|
pub fn write_byte(&self, value: u8) {
|
|
|
|
while self.tx_fifo_full() {}
|
|
|
|
|
|
|
|
self.regs.tx_rx_fifo.write(
|
|
|
|
regs::TxRxFifo::zeroed()
|
|
|
|
.data(value.into())
|
|
|
|
);
|
2019-05-05 20:56:23 +08:00
|
|
|
}
|
|
|
|
|
2019-05-23 21:50:53 +08:00
|
|
|
pub fn configure(&self, baudrate: u32) {
|
2019-05-22 07:42:00 +08:00
|
|
|
// Configure UART character frame
|
2019-05-07 23:46:37 +08:00
|
|
|
// * Disable clock-divider
|
|
|
|
// * 8-bit
|
|
|
|
// * 1 stop bit
|
|
|
|
// * Normal channel mode
|
2019-05-22 07:42:00 +08:00
|
|
|
// * No parity
|
2019-05-21 08:53:59 +08:00
|
|
|
let parity_mode = regs::ParityMode::None;
|
2019-05-07 23:46:37 +08:00
|
|
|
self.regs.mode.write(
|
|
|
|
regs::Mode::zeroed()
|
|
|
|
.par(parity_mode as u8)
|
2019-05-21 08:53:59 +08:00
|
|
|
.chmode(regs::ChannelMode::Normal as u8)
|
2019-05-07 23:46:37 +08:00
|
|
|
);
|
|
|
|
|
|
|
|
// Configure the Baud Rate
|
|
|
|
self.disable_rx();
|
|
|
|
self.disable_tx();
|
|
|
|
|
2019-05-23 21:50:53 +08:00
|
|
|
baud_rate_gen::configure(&self.regs, UART_REF_CLK, baudrate);
|
2019-05-07 23:46:37 +08:00
|
|
|
|
2019-05-21 07:30:54 +08:00
|
|
|
// Enable controller
|
2019-05-07 23:46:37 +08:00
|
|
|
self.reset_rx();
|
|
|
|
self.reset_tx();
|
2019-05-21 08:53:59 +08:00
|
|
|
self.wait_reset();
|
2019-05-07 23:46:37 +08:00
|
|
|
self.enable_rx();
|
|
|
|
self.enable_tx();
|
2019-05-21 07:30:54 +08:00
|
|
|
|
|
|
|
self.set_rx_timeout(false);
|
|
|
|
self.set_break(false, true);
|
2019-05-07 23:46:37 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
fn disable_rx(&self) {
|
|
|
|
self.regs.control.modify(|_, w| {
|
|
|
|
w.rxen(false)
|
|
|
|
.rxdis(true)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
fn disable_tx(&self) {
|
|
|
|
self.regs.control.modify(|_, w| {
|
|
|
|
w.txen(false)
|
|
|
|
.txdis(true)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
fn enable_rx(&self) {
|
|
|
|
self.regs.control.modify(|_, w| {
|
|
|
|
w.rxen(true)
|
|
|
|
.rxdis(false)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
fn enable_tx(&self) {
|
|
|
|
self.regs.control.modify(|_, w| {
|
|
|
|
w.txen(true)
|
|
|
|
.txdis(false)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
fn reset_rx(&self) {
|
|
|
|
self.regs.control.modify(|_, w| {
|
|
|
|
w.rxrst(true)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
fn reset_tx(&self) {
|
|
|
|
self.regs.control.modify(|_, w| {
|
|
|
|
w.txrst(true)
|
|
|
|
})
|
|
|
|
}
|
2019-05-05 20:56:23 +08:00
|
|
|
|
2019-05-21 08:53:59 +08:00
|
|
|
/// Wait for `reset_rx()` or `reset_tx()` to complete
|
|
|
|
fn wait_reset(&self) {
|
|
|
|
let mut pending = true;
|
|
|
|
while pending {
|
|
|
|
let control = self.regs.control.read();
|
|
|
|
pending = control.rxrst() || control.txrst();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-21 07:30:54 +08:00
|
|
|
fn set_break(&self, startbrk: bool, stopbrk: bool) {
|
|
|
|
self.regs.control.modify(|_, w| {
|
|
|
|
w.sttbrk(startbrk)
|
|
|
|
.stpbrk(stopbrk)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0 disables
|
|
|
|
fn set_rx_timeout(&self, enable: bool) {
|
|
|
|
self.regs.control.modify(|_, w| {
|
|
|
|
w.rstto(enable)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2019-05-07 23:46:37 +08:00
|
|
|
pub fn tx_fifo_full(&self) -> bool {
|
|
|
|
self.regs.channel_sts.read().txfull()
|
2019-05-05 20:56:23 +08:00
|
|
|
}
|
2019-05-23 21:36:34 +08:00
|
|
|
|
|
|
|
pub fn tx_fifo_empty(&self) -> bool {
|
|
|
|
self.regs.channel_sts.read().txempty()
|
|
|
|
}
|
2019-05-05 20:56:23 +08:00
|
|
|
}
|
2019-05-07 22:45:31 +08:00
|
|
|
|
|
|
|
impl fmt::Write for Uart {
|
|
|
|
fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> {
|
2019-05-23 21:36:34 +08:00
|
|
|
while !self.tx_fifo_empty() {}
|
|
|
|
|
2019-05-07 22:45:31 +08:00
|
|
|
for b in s.bytes() {
|
|
|
|
self.write_byte(b);
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|