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 r0::zero_bss;
|
||||
|
||||
mod regs;
|
||||
mod cortex_a9;
|
||||
mod slcr;
|
||||
mod uart;
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
59
src/slcr.rs
59
src/slcr.rs
|
@ -1,13 +1,11 @@
|
|||
use core::ops::RangeInclusive;
|
||||
use volatile_register::{RO, WO, RW};
|
||||
use bit_field::BitField;
|
||||
|
||||
use crate::{register, register_bit, register_bits, regs::Register};
|
||||
|
||||
#[repr(packed)]
|
||||
pub struct UartClkCtrl {
|
||||
pub reg: RW<u32>,
|
||||
}
|
||||
|
||||
register!(uart_clk_ctrl, UartClkCtrl, u32);
|
||||
register_bit!(uart_clk_ctrl, clkact0, 0);
|
||||
register_bit!(uart_clk_ctrl, clkact1, 1);
|
||||
register_bits!(uart_clk_ctrl, divisor, u8, 8, 13);
|
||||
impl UartClkCtrl {
|
||||
const ADDR: *mut Self = 0xF8000154 as *mut _;
|
||||
|
||||
|
@ -15,26 +13,19 @@ impl UartClkCtrl {
|
|||
unsafe { &mut *Self::ADDR }
|
||||
}
|
||||
|
||||
const DIVISOR: RangeInclusive<usize> = 8..=13;
|
||||
const CLKACT1: usize = 1;
|
||||
const CLKACT0: usize = 0;
|
||||
|
||||
pub fn enable_uart0(&self) {
|
||||
unsafe {
|
||||
self.reg.modify(|mut x| {
|
||||
x.set_bits(Self::DIVISOR, 0x14);
|
||||
x.set_bit(Self::CLKACT0, true);
|
||||
x
|
||||
self.modify(|_, w| {
|
||||
w.clkact0(true)
|
||||
.divisor(0x14)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(packed)]
|
||||
pub struct UartRstCtrl {
|
||||
pub reg: RW<u32>,
|
||||
}
|
||||
|
||||
register!(uart_rst_ctrl, UartRstCtrl, u32);
|
||||
register_bit!(uart_rst_ctrl, uart0_ref_rst, 3);
|
||||
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 {
|
||||
const ADDR: *mut Self = 0xF8000228 as *mut _;
|
||||
|
||||
|
@ -42,29 +33,13 @@ impl UartRstCtrl {
|
|||
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) {
|
||||
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) {
|
||||
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
|
||||
});
|
||||
}
|
||||
|
|
149
src/uart/regs.rs
149
src/uart/regs.rs
|
@ -1,28 +1,61 @@
|
|||
use volatile_register::{RO, WO, RW};
|
||||
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)]
|
||||
pub struct RegisterBlock {
|
||||
pub control: RW<u32>,
|
||||
pub mode: RW<u32>,
|
||||
pub intrpt_en: RW<u32>,
|
||||
pub intrpt_dis: RW<u32>,
|
||||
pub intrpt_mask: RO<u32>,
|
||||
pub chnl_int_sts: WO<u32>,
|
||||
pub baud_rate_gen: RW<u32>,
|
||||
pub rcvr_timeout: RW<u32>,
|
||||
pub rcvr_fifo_trigger_level: RW<u32>,
|
||||
pub modem_ctrl: RW<u32>,
|
||||
pub modem_sts: RW<u32>,
|
||||
pub channel_sts: RO<u32>,
|
||||
pub tx_rx_fifo: RW<u32>,
|
||||
pub baud_rate_divider: RW<u32>,
|
||||
pub flow_delay: RW<u32>,
|
||||
pub reserved0: RO<u32>,
|
||||
pub reserved1: RO<u32>,
|
||||
pub tx_fifo_trigger_level: RW<u32>,
|
||||
control: Control,
|
||||
mode: Mode,
|
||||
intrpt_en: RW<u32>,
|
||||
intrpt_dis: RW<u32>,
|
||||
intrpt_mask: RO<u32>,
|
||||
chnl_int_sts: WO<u32>,
|
||||
baud_rate_gen: BaudRateGen,
|
||||
rcvr_timeout: RW<u32>,
|
||||
rcvr_fifo_trigger_level: RW<u32>,
|
||||
modem_ctrl: RW<u32>,
|
||||
modem_sts: RW<u32>,
|
||||
channel_sts: ChannelSts,
|
||||
tx_rx_fifo: TxRxFifo,
|
||||
baud_rate_divider: BaudRateDiv,
|
||||
flow_delay: RW<u32>,
|
||||
reserved0: RO<u32>,
|
||||
reserved1: RO<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 {
|
||||
const UART0: *mut Self = 0xE0000000 as *mut _;
|
||||
const UART1: *mut Self = 0xE0001000 as *mut _;
|
||||
|
@ -36,90 +69,74 @@ impl RegisterBlock {
|
|||
}
|
||||
|
||||
pub fn configure(&self) {
|
||||
unsafe {
|
||||
// Confiugre UART character frame
|
||||
// * Disable clock-divider
|
||||
// * 8-bit
|
||||
// * no parity
|
||||
// * 1 stop bit
|
||||
// * Normal channel mode
|
||||
self.mode.write(0x20);
|
||||
// * no parity
|
||||
let parity_mode = ParityMode::ForceTo0;
|
||||
self.mode.write(Mode::zeroed().par(parity_mode as u8));
|
||||
|
||||
// Configure the Buad Rate
|
||||
// Configure the Baud Rate
|
||||
self.disable_rx();
|
||||
self.disable_tx();
|
||||
|
||||
// 9,600 baud
|
||||
self.baud_rate_gen.write(651);
|
||||
self.baud_rate_divider.write(7);
|
||||
self.baud_rate_gen.write(BaudRateGen::zeroed().cd(651));
|
||||
self.baud_rate_divider.write(BaudRateDiv::zeroed().bdiv(7));
|
||||
|
||||
self.reset_rx();
|
||||
self.reset_tx();
|
||||
self.enable_rx();
|
||||
self.enable_tx();
|
||||
}
|
||||
|
||||
pub fn write_byte(&self, value: u8) {
|
||||
self.tx_rx_fifo.write(TxRxFifo::zeroed().data(value.into()));
|
||||
}
|
||||
|
||||
pub unsafe fn write_byte(&self, value: u8) {
|
||||
self.tx_rx_fifo.write(value.into());
|
||||
}
|
||||
|
||||
const CONTROL_RXEN: usize = 2;
|
||||
const CONTROL_RXDIS: usize = 3;
|
||||
const CONTROL_TXEN: usize = 4;
|
||||
const CONTROL_TXDIS: usize = 5;
|
||||
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
|
||||
fn disable_rx(&self) {
|
||||
self.control.modify(|_, w| {
|
||||
w.rxen(false)
|
||||
.rxdis(true)
|
||||
})
|
||||
}
|
||||
|
||||
unsafe fn disable_tx(&self) {
|
||||
self.control.modify(|mut x| {
|
||||
x.set_bit(Self::CONTROL_TXEN, false);
|
||||
x.set_bit(Self::CONTROL_TXDIS, true);
|
||||
x
|
||||
fn disable_tx(&self) {
|
||||
self.control.modify(|_, w| {
|
||||
w.txen(false)
|
||||
.txdis(true)
|
||||
})
|
||||
}
|
||||
|
||||
unsafe fn enable_rx(&self) {
|
||||
self.control.modify(|mut x| {
|
||||
x.set_bit(Self::CONTROL_RXEN, true);
|
||||
x.set_bit(Self::CONTROL_RXDIS, false);
|
||||
x
|
||||
fn enable_rx(&self) {
|
||||
self.control.modify(|_, w| {
|
||||
w.rxen(true)
|
||||
.rxdis(false)
|
||||
})
|
||||
}
|
||||
|
||||
unsafe fn enable_tx(&self) {
|
||||
self.control.modify(|mut x| {
|
||||
x.set_bit(Self::CONTROL_TXEN, true);
|
||||
x.set_bit(Self::CONTROL_TXDIS, false);
|
||||
x
|
||||
fn enable_tx(&self) {
|
||||
self.control.modify(|_, w| {
|
||||
w.txen(true)
|
||||
.txdis(false)
|
||||
})
|
||||
}
|
||||
|
||||
unsafe fn reset_rx(&self) {
|
||||
self.control.modify(|mut x| {
|
||||
x.set_bit(Self::CONTROL_RXRST, true);
|
||||
x
|
||||
fn reset_rx(&self) {
|
||||
self.control.modify(|_, w| {
|
||||
w.rxrst(true)
|
||||
})
|
||||
}
|
||||
|
||||
unsafe fn reset_tx(&self) {
|
||||
self.control.modify(|mut x| {
|
||||
x.set_bit(Self::CONTROL_TXRST, true);
|
||||
x
|
||||
fn reset_tx(&self) {
|
||||
self.control.modify(|_, w| {
|
||||
w.txrst(true)
|
||||
})
|
||||
}
|
||||
|
||||
const CHANNEL_STS_TXFULL: usize = 4;
|
||||
|
||||
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