forked from M-Labs/zynq-rs
regs macros
This commit is contained in:
parent
9b414e2408
commit
55957eea09
@ -7,6 +7,7 @@
|
|||||||
use panic_abort as _;
|
use panic_abort as _;
|
||||||
use r0::zero_bss;
|
use r0::zero_bss;
|
||||||
|
|
||||||
|
mod regs;
|
||||||
mod cortex_a9;
|
mod cortex_a9;
|
||||||
mod slcr;
|
mod slcr;
|
||||||
mod uart;
|
mod uart;
|
||||||
|
108
src/regs.rs
Normal file
108
src/regs.rs
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
//! Interface to peripheral registers akin to the code that svd2rust
|
||||||
|
//! generates.
|
||||||
|
|
||||||
|
use volatile_register::{RO, WO, RW};
|
||||||
|
use bit_field::BitField;
|
||||||
|
|
||||||
|
pub trait Register {
|
||||||
|
type R;
|
||||||
|
type W;
|
||||||
|
|
||||||
|
fn read(&self) -> Self::R;
|
||||||
|
fn write(&self, w: Self::W);
|
||||||
|
fn modify<F: FnOnce(Self::R, Self::W) -> Self::W>(&self, f: F);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! register {
|
||||||
|
($mod_name: ident, $struct_name: ident, $inner: ty) => (
|
||||||
|
#[repr(packed)]
|
||||||
|
pub struct $struct_name {
|
||||||
|
inner: RW<$inner>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod $mod_name {
|
||||||
|
pub struct Read {
|
||||||
|
pub inner: $inner,
|
||||||
|
}
|
||||||
|
pub struct Write {
|
||||||
|
pub inner: $inner,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl $struct_name {
|
||||||
|
pub fn zeroed() -> $mod_name::Write {
|
||||||
|
$mod_name::Write { inner: 0 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl crate::regs::Register for $struct_name {
|
||||||
|
type R = $mod_name::Read;
|
||||||
|
type W = $mod_name::Write;
|
||||||
|
|
||||||
|
fn read(&self) -> Self::R {
|
||||||
|
let inner = self.inner.read();
|
||||||
|
$mod_name::Read { inner }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write(&self, w: Self::W) {
|
||||||
|
unsafe {
|
||||||
|
self.inner.write(w.inner);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn modify<F: FnOnce(Self::R, Self::W) -> Self::W>(&self, f: F) {
|
||||||
|
unsafe {
|
||||||
|
self.inner.modify(|inner| {
|
||||||
|
f($mod_name::Read { inner }, $mod_name::Write { inner })
|
||||||
|
.inner
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! register_bit {
|
||||||
|
($mod_name: ident, $name: ident, $bit: expr) => (
|
||||||
|
impl $mod_name::Read {
|
||||||
|
fn $name(&self) -> bool {
|
||||||
|
use bit_field::BitField;
|
||||||
|
|
||||||
|
self.inner.get_bit($bit)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl $mod_name::Write {
|
||||||
|
fn $name(mut self, value: bool) -> Self {
|
||||||
|
use bit_field::BitField;
|
||||||
|
|
||||||
|
self.inner.set_bit($bit, value);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! register_bits {
|
||||||
|
($mod_name: ident, $name: ident, $type: ty, $bit_begin: expr, $bit_end: expr) => (
|
||||||
|
impl $mod_name::Read {
|
||||||
|
fn $name(&self) -> $type {
|
||||||
|
use bit_field::BitField;
|
||||||
|
|
||||||
|
self.inner.get_bits($bit_begin..=$bit_end) as $type
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl $mod_name::Write {
|
||||||
|
fn $name(mut self, value: $type) -> Self {
|
||||||
|
use bit_field::BitField;
|
||||||
|
|
||||||
|
self.inner.set_bits($bit_begin..=$bit_end, value.into());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
61
src/slcr.rs
61
src/slcr.rs
@ -1,40 +1,31 @@
|
|||||||
use core::ops::RangeInclusive;
|
|
||||||
use volatile_register::{RO, WO, RW};
|
use volatile_register::{RO, WO, RW};
|
||||||
use bit_field::BitField;
|
|
||||||
|
|
||||||
|
use crate::{register, register_bit, register_bits, regs::Register};
|
||||||
|
|
||||||
#[repr(packed)]
|
register!(uart_clk_ctrl, UartClkCtrl, u32);
|
||||||
pub struct UartClkCtrl {
|
register_bit!(uart_clk_ctrl, clkact0, 0);
|
||||||
pub reg: RW<u32>,
|
register_bit!(uart_clk_ctrl, clkact1, 1);
|
||||||
}
|
register_bits!(uart_clk_ctrl, divisor, u8, 8, 13);
|
||||||
|
|
||||||
impl UartClkCtrl {
|
impl UartClkCtrl {
|
||||||
const ADDR: *mut Self = 0xF8000154 as *mut _;
|
const ADDR: *mut Self = 0xF8000154 as *mut _;
|
||||||
|
|
||||||
pub fn new() -> &'static mut Self {
|
pub fn new() -> &'static mut Self {
|
||||||
unsafe { &mut *Self::ADDR }
|
unsafe { &mut *Self::ADDR }
|
||||||
}
|
}
|
||||||
|
|
||||||
const DIVISOR: RangeInclusive<usize> = 8..=13;
|
|
||||||
const CLKACT1: usize = 1;
|
|
||||||
const CLKACT0: usize = 0;
|
|
||||||
|
|
||||||
pub fn enable_uart0(&self) {
|
pub fn enable_uart0(&self) {
|
||||||
unsafe {
|
self.modify(|_, w| {
|
||||||
self.reg.modify(|mut x| {
|
w.clkact0(true)
|
||||||
x.set_bits(Self::DIVISOR, 0x14);
|
.divisor(0x14)
|
||||||
x.set_bit(Self::CLKACT0, true);
|
})
|
||||||
x
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(packed)]
|
register!(uart_rst_ctrl, UartRstCtrl, u32);
|
||||||
pub struct UartRstCtrl {
|
register_bit!(uart_rst_ctrl, uart0_ref_rst, 3);
|
||||||
pub reg: RW<u32>,
|
register_bit!(uart_rst_ctrl, uart1_ref_rst, 2);
|
||||||
}
|
register_bit!(uart_rst_ctrl, uart0_cpu1x_rst, 1);
|
||||||
|
register_bit!(uart_rst_ctrl, uart1_cpu1x_rst, 0);
|
||||||
impl UartRstCtrl {
|
impl UartRstCtrl {
|
||||||
const ADDR: *mut Self = 0xF8000228 as *mut _;
|
const ADDR: *mut Self = 0xF8000228 as *mut _;
|
||||||
|
|
||||||
@ -42,29 +33,13 @@ impl UartRstCtrl {
|
|||||||
unsafe { &mut *Self::ADDR }
|
unsafe { &mut *Self::ADDR }
|
||||||
}
|
}
|
||||||
|
|
||||||
const UART1_REF_RST: usize = 3;
|
|
||||||
const UART0_REF_RST: usize = 2;
|
|
||||||
const UART1_CPU1X_RST: usize = 1;
|
|
||||||
const UART0_CPU1X_RST: usize = 0;
|
|
||||||
|
|
||||||
pub fn reset_uart0(&self) {
|
pub fn reset_uart0(&self) {
|
||||||
unsafe { toggle(&self.reg, Self::UART0_REF_RST); }
|
self.modify(|_, w| w.uart0_ref_rst(true));
|
||||||
|
self.modify(|_, w| w.uart0_ref_rst(false));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn reset_uart1(&self) {
|
pub fn reset_uart1(&self) {
|
||||||
unsafe { toggle(&self.reg, Self::UART1_REF_RST); }
|
self.modify(|_, w| w.uart1_ref_rst(true));
|
||||||
|
self.modify(|_, w| w.uart1_ref_rst(false));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn toggle<T: BitField + Copy>(reg: &RW<T>, bit: usize) {
|
|
||||||
reg.modify(|x| {
|
|
||||||
let mut x = x.clone();
|
|
||||||
x.set_bit(bit, true);
|
|
||||||
x
|
|
||||||
});
|
|
||||||
reg.modify(|x| {
|
|
||||||
let mut x = x.clone();
|
|
||||||
x.set_bit(bit, false);
|
|
||||||
x
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
@ -11,9 +11,9 @@ impl Uart {
|
|||||||
uart_rst_ctrl.reset_uart0();
|
uart_rst_ctrl.reset_uart0();
|
||||||
// TODO: Route UART 0 RxD/TxD Signals to MIO Pins
|
// TODO: Route UART 0 RxD/TxD Signals to MIO Pins
|
||||||
|
|
||||||
// a. Clock divisor, slcr.UART_CLK_CTRL[DIVISOR] = 0x14.
|
// a. Clock divisor, slcr.UART_CLK_CTRL[DIVISOR] = 0x14.
|
||||||
// b. Select the IO PLL, slcr.UART_CLK_CTRL[SRCSEL] = 0.
|
// b. Select the IO PLL, slcr.UART_CLK_CTRL[SRCSEL] = 0.
|
||||||
// c. Enable the UART 0 Reference clock, slcr.UART_CLK_CTRL [CLKACT0] = 1.
|
// c. Enable the UART 0 Reference clock, slcr.UART_CLK_CTRL [CLKACT0] = 1.
|
||||||
// d. Disable UART 1 Reference clock, slcr.UART_CLK_CTRL [CLKACT1] bit = 0.
|
// d. Disable UART 1 Reference clock, slcr.UART_CLK_CTRL [CLKACT1] bit = 0.
|
||||||
let uart_clk_ctrl = super::slcr::UartClkCtrl::new();
|
let uart_clk_ctrl = super::slcr::UartClkCtrl::new();
|
||||||
uart_clk_ctrl.enable_uart0();
|
uart_clk_ctrl.enable_uart0();
|
||||||
|
171
src/uart/regs.rs
171
src/uart/regs.rs
@ -1,28 +1,61 @@
|
|||||||
use volatile_register::{RO, WO, RW};
|
use volatile_register::{RO, WO, RW};
|
||||||
use bit_field::BitField;
|
use bit_field::BitField;
|
||||||
|
|
||||||
|
use crate::{register, register_bit, register_bits, regs::Register};
|
||||||
|
|
||||||
|
#[repr(u8)]
|
||||||
|
pub enum ParityMode {
|
||||||
|
EvenParity = 0b000,
|
||||||
|
OddParity = 0b001,
|
||||||
|
ForceTo0 = 0b010,
|
||||||
|
ForceTo1 = 0b011,
|
||||||
|
}
|
||||||
|
|
||||||
#[repr(packed)]
|
#[repr(packed)]
|
||||||
pub struct RegisterBlock {
|
pub struct RegisterBlock {
|
||||||
pub control: RW<u32>,
|
control: Control,
|
||||||
pub mode: RW<u32>,
|
mode: Mode,
|
||||||
pub intrpt_en: RW<u32>,
|
intrpt_en: RW<u32>,
|
||||||
pub intrpt_dis: RW<u32>,
|
intrpt_dis: RW<u32>,
|
||||||
pub intrpt_mask: RO<u32>,
|
intrpt_mask: RO<u32>,
|
||||||
pub chnl_int_sts: WO<u32>,
|
chnl_int_sts: WO<u32>,
|
||||||
pub baud_rate_gen: RW<u32>,
|
baud_rate_gen: BaudRateGen,
|
||||||
pub rcvr_timeout: RW<u32>,
|
rcvr_timeout: RW<u32>,
|
||||||
pub rcvr_fifo_trigger_level: RW<u32>,
|
rcvr_fifo_trigger_level: RW<u32>,
|
||||||
pub modem_ctrl: RW<u32>,
|
modem_ctrl: RW<u32>,
|
||||||
pub modem_sts: RW<u32>,
|
modem_sts: RW<u32>,
|
||||||
pub channel_sts: RO<u32>,
|
channel_sts: ChannelSts,
|
||||||
pub tx_rx_fifo: RW<u32>,
|
tx_rx_fifo: TxRxFifo,
|
||||||
pub baud_rate_divider: RW<u32>,
|
baud_rate_divider: BaudRateDiv,
|
||||||
pub flow_delay: RW<u32>,
|
flow_delay: RW<u32>,
|
||||||
pub reserved0: RO<u32>,
|
reserved0: RO<u32>,
|
||||||
pub reserved1: RO<u32>,
|
reserved1: RO<u32>,
|
||||||
pub tx_fifo_trigger_level: RW<u32>,
|
tx_fifo_trigger_level: RW<u32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
register!(control, Control, u32);
|
||||||
|
register_bit!(control, rxrst, 0);
|
||||||
|
register_bit!(control, txrst, 1);
|
||||||
|
register_bit!(control, rxen, 2);
|
||||||
|
register_bit!(control, rxdis, 3);
|
||||||
|
register_bit!(control, txen, 4);
|
||||||
|
register_bit!(control, txdis, 5);
|
||||||
|
|
||||||
|
register!(mode, Mode, u32);
|
||||||
|
register_bits!(mode, par, u8, 3, 5);
|
||||||
|
|
||||||
|
register!(baud_rate_gen, BaudRateGen, u32);
|
||||||
|
register_bits!(baud_rate_gen, cd, u16, 0, 15);
|
||||||
|
|
||||||
|
register!(channel_sts, ChannelSts, u32);
|
||||||
|
register_bit!(channel_sts, txfull, 4);
|
||||||
|
|
||||||
|
register!(tx_rx_fifo, TxRxFifo, u32);
|
||||||
|
register_bits!(tx_rx_fifo, data, u32, 0, 31);
|
||||||
|
|
||||||
|
register!(baud_rate_div, BaudRateDiv, u32);
|
||||||
|
register_bits!(baud_rate_div, bdiv, u8, 0, 7);
|
||||||
|
|
||||||
impl RegisterBlock {
|
impl RegisterBlock {
|
||||||
const UART0: *mut Self = 0xE0000000 as *mut _;
|
const UART0: *mut Self = 0xE0000000 as *mut _;
|
||||||
const UART1: *mut Self = 0xE0001000 as *mut _;
|
const UART1: *mut Self = 0xE0001000 as *mut _;
|
||||||
@ -36,90 +69,74 @@ impl RegisterBlock {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn configure(&self) {
|
pub fn configure(&self) {
|
||||||
unsafe {
|
// Confiugre UART character frame
|
||||||
// Confiugre UART character frame
|
// * Disable clock-divider
|
||||||
// * Disable clock-divider
|
// * 8-bit
|
||||||
// * 8-bit
|
// * 1 stop bit
|
||||||
// * no parity
|
// * Normal channel mode
|
||||||
// * 1 stop bit
|
// * no parity
|
||||||
// * Normal channel mode
|
let parity_mode = ParityMode::ForceTo0;
|
||||||
self.mode.write(0x20);
|
self.mode.write(Mode::zeroed().par(parity_mode as u8));
|
||||||
|
|
||||||
// Configure the Buad Rate
|
// Configure the Baud Rate
|
||||||
self.disable_rx();
|
self.disable_rx();
|
||||||
self.disable_tx();
|
self.disable_tx();
|
||||||
|
|
||||||
// 9,600 baud
|
// 9,600 baud
|
||||||
self.baud_rate_gen.write(651);
|
self.baud_rate_gen.write(BaudRateGen::zeroed().cd(651));
|
||||||
self.baud_rate_divider.write(7);
|
self.baud_rate_divider.write(BaudRateDiv::zeroed().bdiv(7));
|
||||||
|
|
||||||
self.reset_rx();
|
self.reset_rx();
|
||||||
self.reset_tx();
|
self.reset_tx();
|
||||||
self.enable_rx();
|
self.enable_rx();
|
||||||
self.enable_tx();
|
self.enable_tx();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn write_byte(&self, value: u8) {
|
pub fn write_byte(&self, value: u8) {
|
||||||
self.tx_rx_fifo.write(value.into());
|
self.tx_rx_fifo.write(TxRxFifo::zeroed().data(value.into()));
|
||||||
}
|
}
|
||||||
|
|
||||||
const CONTROL_RXEN: usize = 2;
|
fn disable_rx(&self) {
|
||||||
const CONTROL_RXDIS: usize = 3;
|
self.control.modify(|_, w| {
|
||||||
const CONTROL_TXEN: usize = 4;
|
w.rxen(false)
|
||||||
const CONTROL_TXDIS: usize = 5;
|
.rxdis(true)
|
||||||
const CONTROL_TXRST: usize = 1;
|
|
||||||
const CONTROL_RXRST: usize = 0;
|
|
||||||
|
|
||||||
unsafe fn disable_rx(&self) {
|
|
||||||
self.control.modify(|mut x| {
|
|
||||||
x.set_bit(Self::CONTROL_RXEN, false);
|
|
||||||
x.set_bit(Self::CONTROL_RXDIS, true);
|
|
||||||
x
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn disable_tx(&self) {
|
fn disable_tx(&self) {
|
||||||
self.control.modify(|mut x| {
|
self.control.modify(|_, w| {
|
||||||
x.set_bit(Self::CONTROL_TXEN, false);
|
w.txen(false)
|
||||||
x.set_bit(Self::CONTROL_TXDIS, true);
|
.txdis(true)
|
||||||
x
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn enable_rx(&self) {
|
fn enable_rx(&self) {
|
||||||
self.control.modify(|mut x| {
|
self.control.modify(|_, w| {
|
||||||
x.set_bit(Self::CONTROL_RXEN, true);
|
w.rxen(true)
|
||||||
x.set_bit(Self::CONTROL_RXDIS, false);
|
.rxdis(false)
|
||||||
x
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn enable_tx(&self) {
|
fn enable_tx(&self) {
|
||||||
self.control.modify(|mut x| {
|
self.control.modify(|_, w| {
|
||||||
x.set_bit(Self::CONTROL_TXEN, true);
|
w.txen(true)
|
||||||
x.set_bit(Self::CONTROL_TXDIS, false);
|
.txdis(false)
|
||||||
x
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn reset_rx(&self) {
|
fn reset_rx(&self) {
|
||||||
self.control.modify(|mut x| {
|
self.control.modify(|_, w| {
|
||||||
x.set_bit(Self::CONTROL_RXRST, true);
|
w.rxrst(true)
|
||||||
x
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn reset_tx(&self) {
|
fn reset_tx(&self) {
|
||||||
self.control.modify(|mut x| {
|
self.control.modify(|_, w| {
|
||||||
x.set_bit(Self::CONTROL_TXRST, true);
|
w.txrst(true)
|
||||||
x
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const CHANNEL_STS_TXFULL: usize = 4;
|
|
||||||
|
|
||||||
pub fn tx_fifo_full(&self) -> bool {
|
pub fn tx_fifo_full(&self) -> bool {
|
||||||
self.channel_sts.read().get_bit(Self::CHANNEL_STS_TXFULL)
|
self.channel_sts.read().txfull()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user