zynq-rs/src/uart/mod.rs

215 lines
5.4 KiB
Rust
Raw Normal View History

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
/// Determined through experimentation. Actually supposed to be
/// 1 GHz (IO PLL) / 0x14 (slcr.UART_CLK_CTRL[DIVISOR]) = 50 MHz.
2019-05-25 08:38:05 +08:00
#[cfg(feature = "target_zc706")]
const UART_REF_CLK: u32 = 45_000_000;
2019-05-25 08:38:05 +08:00
#[cfg(feature = "target_cora_z7_10")]
const UART_REF_CLK: u32 = 66_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-25 08:38:05 +08:00
#[cfg(feature = "target_zc706")]
pub fn serial(baudrate: u32) -> Self {
2019-05-23 23:52:06 +08:00
slcr::RegisterBlock::unlocked(|slcr| {
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)
2019-05-25 08:38:05 +08:00
.io_type(slcr::IoBufferType::Lvcmos18)
2019-05-23 23:52:06 +08:00
.pullup(true)
);
// RX pin
slcr.mio_pin_49.write(
slcr::MioPin49::zeroed()
.tri_enable(true)
.l3_sel(0b111)
2019-05-25 08:38:05 +08:00
.io_type(slcr::IoBufferType::Lvcmos18)
2019-05-23 23:52:06 +08:00
.pullup(true)
);
2019-05-25 08:38:05 +08:00
});
Self::uart1(baudrate)
}
2019-05-21 07:30:54 +08:00
2019-05-25 08:38:05 +08:00
#[cfg(feature = "target_cora_z7_10")]
pub fn serial(baudrate: u32) -> Self {
slcr::RegisterBlock::unlocked(|slcr| {
// Route UART 0 RxD/TxD Signals to MIO Pins
// TX pin
slcr.mio_pin_15.write(
slcr::MioPin15::zeroed()
.l3_sel(0b111)
.io_type(slcr::IoBufferType::Lvcmos33)
.pullup(true)
);
// RX pin
slcr.mio_pin_14.write(
slcr::MioPin14::zeroed()
.tri_enable(true)
.l3_sel(0b111)
.io_type(slcr::IoBufferType::Lvcmos33)
.pullup(true)
);
});
Self::uart0(baudrate)
}
pub fn uart0(baudrate: u32) -> Self {
slcr::RegisterBlock::unlocked(|slcr| {
slcr.uart_rst_ctrl.reset_uart0();
slcr.aper_clk_ctrl.enable_uart0();
slcr.uart_clk_ctrl.enable_uart0();
});
let mut self_ = Uart {
regs: regs::RegisterBlock::uart0(),
};
self_.configure(baudrate);
self_
}
pub fn uart1(baudrate: u32) -> Self {
slcr::RegisterBlock::unlocked(|slcr| {
slcr.uart_rst_ctrl.reset_uart1();
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
});
let mut self_ = Uart {
2019-05-21 07:30:54 +08:00
regs: regs::RegisterBlock::uart1(),
2019-05-07 23:46:37 +08:00
};
self_.configure(baudrate);
2019-05-07 23:46:37 +08:00
self_
2019-05-05 20:56:23 +08:00
}
pub fn write_byte(&mut self, value: u8) {
2019-05-07 23:46:37 +08:00
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
}
pub fn configure(&mut 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-07 23:46:37 +08:00
self.regs.mode.write(
regs::Mode::zeroed()
2019-05-24 00:23:51 +08:00
.par(regs::ParityMode::None)
.chmode(regs::ChannelMode::Normal)
2019-05-07 23:46:37 +08:00
);
// Configure the Baud Rate
self.disable_rx();
self.disable_tx();
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(&mut self) {
2019-05-07 23:46:37 +08:00
self.regs.control.modify(|_, w| {
w.rxen(false)
.rxdis(true)
})
}
fn disable_tx(&mut self) {
2019-05-07 23:46:37 +08:00
self.regs.control.modify(|_, w| {
w.txen(false)
.txdis(true)
})
}
fn enable_rx(&mut self) {
2019-05-07 23:46:37 +08:00
self.regs.control.modify(|_, w| {
w.rxen(true)
.rxdis(false)
})
}
fn enable_tx(&mut self) {
2019-05-07 23:46:37 +08:00
self.regs.control.modify(|_, w| {
w.txen(true)
.txdis(false)
})
}
fn reset_rx(&mut self) {
2019-05-07 23:46:37 +08:00
self.regs.control.modify(|_, w| {
w.rxrst(true)
})
}
fn reset_tx(&mut self) {
2019-05-07 23:46:37 +08:00
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();
}
}
fn set_break(&mut self, startbrk: bool, stopbrk: bool) {
2019-05-21 07:30:54 +08:00
self.regs.control.modify(|_, w| {
w.sttbrk(startbrk)
.stpbrk(stopbrk)
})
}
// 0 disables
fn set_rx_timeout(&mut self, enable: bool) {
2019-05-21 07:30:54 +08:00
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
}
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> {
while !self.tx_fifo_empty() {}
2019-05-07 22:45:31 +08:00
for b in s.bytes() {
self.write_byte(b);
}
Ok(())
}
}