diff --git a/src/regs.rs b/src/regs.rs index 32b106f..433f29f 100644 --- a/src/regs.rs +++ b/src/regs.rs @@ -164,6 +164,34 @@ macro_rules! register_bits { ); } +/// Define a multi-bit field of a register, coerced to a certain type +/// +/// Because read bits are just transmuted to the `$type`, its +/// definition must be annotated with `#[repr($bit_type)]`! +#[macro_export] +macro_rules! register_bits_typed { + ($mod_name: ident, $name: ident, $bit_type: ty, $type: ty, $bit_begin: expr, $bit_end: expr) => ( + impl $mod_name::Read { + pub fn $name(&self) -> $type { + use bit_field::BitField; + + let bits = self.inner.get_bits($bit_begin..=$bit_end) as $bit_type; + unsafe { core::mem::transmute(bits) } + } + } + + impl $mod_name::Write { + pub fn $name(mut self, value: $type) -> Self { + use bit_field::BitField; + + let bits = (value as $bit_type).into(); + self.inner.set_bits($bit_begin..=$bit_end, bits); + self + } + } + ); +} + #[macro_export] macro_rules! register_at { ($name: ident, $addr: expr, $ctor: ident) => ( diff --git a/src/slcr.rs b/src/slcr.rs index 0a13fdd..abebd28 100644 --- a/src/slcr.rs +++ b/src/slcr.rs @@ -1,8 +1,11 @@ ///! Register definitions for System Level Control use volatile_register::{RO, WO, RW}; -use crate::{register, register_bit, register_bits, register_at, regs::RegisterW, regs::RegisterRW}; +use crate::{register, register_at, + register_bit, register_bits, register_bits_typed, + regs::RegisterW, regs::RegisterRW}; +#[repr(u8)] pub enum PllSource { IoPll = 0b00, ArmPll = 0b10, @@ -246,7 +249,7 @@ register!(uart_clk_ctrl, UartClkCtrl, RW, u32); register_bit!(uart_clk_ctrl, clkact0, 0); register_bit!(uart_clk_ctrl, clkact1, 1); register_bits!(uart_clk_ctrl, divisor, u8, 8, 13); -register_bits!(uart_clk_ctrl, srcsel, u8, 4, 5); +register_bits_typed!(uart_clk_ctrl, srcsel, u8, PllSource, 4, 5); register_at!(UartClkCtrl, 0xF8000154, new); impl UartClkCtrl { pub fn enable_uart0(&mut self) { @@ -255,7 +258,7 @@ impl UartClkCtrl { // b. Select the IO PLL, slcr.UART_CLK_CTRL[SRCSEL] = 0. // c. Enable the UART 0 Reference clock, slcr.UART_CLK_CTRL [CLKACT0] = 1. w.divisor(0x14) - .srcsel(PllSource::IoPll as u8) + .srcsel(PllSource::IoPll) .clkact0(true) }) } @@ -266,7 +269,7 @@ impl UartClkCtrl { // b. Select the IO PLL, slcr.UART_CLK_CTRL[SRCSEL] = 0. // c. Enable the UART 1 Reference clock, slcr.UART_CLK_CTRL [CLKACT1] = 1. w.divisor(0x14) - .srcsel(PllSource::IoPll as u8) + .srcsel(PllSource::IoPll) .clkact1(true) }) } diff --git a/src/uart/mod.rs b/src/uart/mod.rs index 6356d02..2986573 100644 --- a/src/uart/mod.rs +++ b/src/uart/mod.rs @@ -65,11 +65,10 @@ impl Uart { // * 1 stop bit // * Normal channel mode // * No parity - let parity_mode = regs::ParityMode::None; self.regs.mode.write( regs::Mode::zeroed() - .par(parity_mode as u8) - .chmode(regs::ChannelMode::Normal as u8) + .par(regs::ParityMode::None) + .chmode(regs::ChannelMode::Normal) ); // Configure the Baud Rate diff --git a/src/uart/regs.rs b/src/uart/regs.rs index 1a5195d..5f75cae 100644 --- a/src/uart/regs.rs +++ b/src/uart/regs.rs @@ -1,7 +1,8 @@ use volatile_register::{RO, WO, RW}; -use crate::{register, register_bit, register_bits, register_at, regs::*}; +use crate::{register, register_bit, register_bits, register_bits_typed, register_at, regs::*}; +#[repr(u8)] pub enum ChannelMode { Normal = 0b00, AutomaticEcho = 0b01, @@ -9,6 +10,7 @@ pub enum ChannelMode { RemoteLoopback = 0b11, } +#[repr(u8)] pub enum ParityMode { EvenParity = 0b000, OddParity = 0b001, @@ -17,6 +19,7 @@ pub enum ParityMode { None = 0b100, } +#[repr(u8)] pub enum StopBits { One = 0b00, OneAndHalf = 0b01, @@ -60,11 +63,11 @@ register_bit!(control, stpbrk, 8); register!(mode, Mode, RW, u32); /// Channel mode: Defines the mode of operation of the UART. -register_bits!(mode, chmode, u8, 8, 9); +register_bits_typed!(mode, chmode, u8, ChannelMode, 8, 9); /// Number of stop bits -register_bits!(mode, nbstop, u8, 6, 7); +register_bits_typed!(mode, nbstop, u8, StopBits, 6, 7); /// Parity type select -register_bits!(mode, par, u8, 3, 5); +register_bits_typed!(mode, par, u8, ParityMode, 3, 5); /// Character length select register_bits!(mode, chrl, u8, 1, 2); /// Clock source select