diff --git a/examples/uart-embedded-io/src/main.rs b/examples/uart-embedded-io/src/main.rs index a29809bf90beafc809f2d70f2b1cbd4b1ce097c7..99dc6dc85d8f3c49772890f8545a4377cd8fd7b1 100644 --- a/examples/uart-embedded-io/src/main.rs +++ b/examples/uart-embedded-io/src/main.rs @@ -14,7 +14,7 @@ use bl_soc::{ GLB, UART, }; use embedded_hal::digital::{OutputPin, PinState}; -use embedded_io::blocking::Write; +use embedded_io::blocking::{Read, Write}; use embedded_time::rate::*; use panic_halt as _; @@ -54,25 +54,47 @@ fn main() -> ! { ); let mut led = gpio.io8.into_floating_output(); - let mut led_state = PinState::High; - let mut counter = 0; + let mut led_state = PinState::Low; + let mut buf = [0u8; 32]; + let mut ch = b'\r'; + + #[rustfmt::skip] + writeln!(serial, "Welcome to console example by bl-soc & embedded-io🦀!").ok(); + writeln!(serial, "Command helps: ").ok(); + writeln!(serial, " led [|on|off|switch]: operate on LED").ok(); loop { - serial - .write_all("Hello Rust from bl-soc by embedded-io🦀!\r\n".as_bytes()) - .ok(); - serial - .write_fmt(format_args!("Counter value: {}\r\n", counter)) - .ok(); - writeln!(serial, "LED state: {:?}", led_state).ok(); + led.set_state(led_state).ok(); serial.flush().ok(); - led.set_state(led_state).ok(); - counter += 1; - led_state = !led_state; + write!(serial, "> ").ok(); + + let mut idx = 0; + while ch == b'\r' || ch == b'\n' { + serial.read_exact(core::slice::from_mut(&mut ch)).ok(); + } + while ch != b'\r' && ch != b'\n' && idx < buf.len() { + if ch == 0x08 && idx > 0 { + // backspace + write!(serial, "\x08 \x08").unwrap(); + idx -= 1; + } else if ch != 0x08 { + write!(serial, "{}", ch as char).unwrap(); + buf[idx] = ch; + idx += 1; + } + serial.read_exact(core::slice::from_mut(&mut ch)).ok(); + } + ch = b'\r'; + writeln!(serial, "").ok(); + let command = core::str::from_utf8(&buf[..idx]).unwrap(); - for _ in 0..100_000 { - unsafe { core::arch::asm!("nop") } + match command.trim() { + "led" => writeln!(serial, "LED state: {:?}", led_state).unwrap(), + "led on" => led_state = PinState::Low, + "led off" => led_state = PinState::High, + "led switch" => led_state = !led_state, + _ => writeln!(serial, "Unknown command: {}", command).unwrap(), } } } diff --git a/src/uart.rs b/src/uart.rs index 5700a7be79e2beff8db6abf6666003016129fadd..99764f99a46ee4fedc42296d1006f32d5d5c3d46 100644 --- a/src/uart.rs +++ b/src/uart.rs @@ -9,6 +9,7 @@ use base_address::BaseAddress; use core::cell::UnsafeCell; #[cfg(any(doc, feature = "glb-v2"))] use core::marker::PhantomData; +use volatile_register::{RO, RW, WO}; #[cfg(any(doc, feature = "glb-v1", feature = "glb-v2"))] use { crate::{clocks::Clocks, GLB}, @@ -27,29 +28,29 @@ impl Alternate for Uart { #[repr(C)] pub struct RegisterBlock { /// Transmit configuration. - pub transmit_config: TRANSMIT_CONFIG, + pub transmit_config: RW, /// Receive configuration. - pub receive_config: RECEIVE_CONFIG, + pub receive_config: RW, /// Bit period in clocks. - pub bit_period: BIT_PERIOD, + pub bit_period: RW, /// Data format configuration. - pub data_config: DATA_CONFIG, + pub data_config: RW, _reserved1: [u8; 0x10], /// Interrupt state register. - pub interrupt_state: INTERRUPT_STATE, + pub interrupt_state: RO, /// Interrupt mask register. - pub interrupt_mask: INTERRUPT_MASK, + pub interrupt_mask: RW, /// Clear interrupt register. - pub interrupt_clear: INTERRUPT_CLEAR, + pub interrupt_clear: WO, /// Interrupt enable register. - pub interrupt_enable: INTERRUPT_ENABLE, + pub interrupt_enable: RW, /// Bus state. - pub bus_state: BUS_STATE, + pub bus_state: RO, _reserved2: [u8; 0x4c], /// First-in first-out queue configuration 0. - pub fifo_config_0: FIFO_CONFIG_0, + pub fifo_config_0: RW, /// First-in first-out queue configuration 1. - pub fifo_config_1: FIFO_CONFIG_1, + pub fifo_config_1: RW, /// Write data into first-in first-out queue. pub data_write: DATA_WRITE, _reserved3: [u8; 0x3], @@ -58,28 +59,10 @@ pub struct RegisterBlock { } /// Transmit configuration register. -#[allow(non_camel_case_types)] -#[repr(transparent)] -pub struct TRANSMIT_CONFIG(UnsafeCell); - -/// Configuration structure for transmit feature. #[derive(Clone, Copy, Debug, PartialEq, Eq, Default)] #[repr(transparent)] pub struct TransmitConfig(u32); -impl TRANSMIT_CONFIG { - /// Read transmit configuration. - #[inline] - pub fn read(&self) -> TransmitConfig { - TransmitConfig(unsafe { self.0.get().read_volatile() }) - } - /// Write transmit configuration. - #[inline] - pub fn write(&self, val: TransmitConfig) { - unsafe { self.0.get().write_volatile(val.0) } - } -} - // TODO: inherent associated types is unstable, put aliases here as WAR /// Register fields aliases, defining the bit field shift and bit length mod transmit_config { @@ -300,28 +283,10 @@ impl TransmitConfig { } /// Receive configuration register. -#[allow(non_camel_case_types)] -#[repr(transparent)] -pub struct RECEIVE_CONFIG(UnsafeCell); - -/// Configuration structure for receive configuration. #[derive(Clone, Copy, Debug, PartialEq, Eq, Default)] #[repr(transparent)] pub struct ReceiveConfig(u32); -impl RECEIVE_CONFIG { - /// Read receive configuration. - #[inline] - pub fn read(&self) -> ReceiveConfig { - ReceiveConfig(unsafe { self.0.get().read_volatile() }) - } - /// Write receive configuration. - #[inline] - pub fn write(&self, val: ReceiveConfig) { - unsafe { self.0.get().write_volatile(val.0) } - } -} - mod receive_config { use crate::BitField; @@ -336,7 +301,6 @@ impl ReceiveConfig { const LIN_RECEIVE: u32 = 1 << 3; const IR_RECEIVE: u32 = 1 << 6; const IR_INVERSE: u32 = 1 << 7; - const CHAR_BIT_COUNT: u32 = 0x3 << 8; const DEGLICH: u32 = 1 << 11; const DEGLICH_CYCLE: u32 = 0xf << 12; const TRANSFER_LENGTH: u32 = 0xffff << 16; @@ -471,16 +435,6 @@ impl ReceiveConfig { _ => unreachable!(), } } - /// Set bit count for each character. - #[inline] - pub const fn set_char_bit_count(self, val: u8) -> Self { - Self(self.0 & !Self::CHAR_BIT_COUNT | ((val as u32) << 8)) - } - /// Get bit count for each character. - #[inline] - pub const fn char_bit_count(self) -> u8 { - ((self.0 & Self::CHAR_BIT_COUNT) >> 8) as u8 - } /// Enable de-glitch function. #[inline] pub const fn enable_deglitch(self) -> Self { @@ -519,23 +473,6 @@ impl ReceiveConfig { } /// Bit period configuration register. -#[allow(non_camel_case_types)] -#[repr(transparent)] -pub struct BIT_PERIOD(UnsafeCell); - -impl BIT_PERIOD { - /// Read data configuration. - #[inline] - pub fn read(&self) -> BitPeriod { - BitPeriod(unsafe { self.0.get().read_volatile() }) - } - /// Write data configuration. - #[inline] - pub fn write(&self, val: BitPeriod) { - unsafe { self.0.get().write_volatile(val.0) } - } -} -/// Configuration structure for bit period. #[derive(Clone, Copy, Debug, PartialEq, Eq, Default)] #[repr(transparent)] pub struct BitPeriod(u32); @@ -567,28 +504,10 @@ impl BitPeriod { } /// Data configuration register. -#[allow(non_camel_case_types)] -#[repr(transparent)] -pub struct DATA_CONFIG(UnsafeCell); - -/// Configuration structure for data format. #[derive(Clone, Copy, Debug, PartialEq, Eq, Default)] #[repr(transparent)] pub struct DataConfig(u32); -impl DATA_CONFIG { - /// Read data configuration. - #[inline] - pub fn read(&self) -> DataConfig { - DataConfig(unsafe { self.0.get().read_volatile() }) - } - /// Write data configuration. - #[inline] - pub fn write(&self, val: DataConfig) { - unsafe { self.0.get().write_volatile(val.0) } - } -} - impl DataConfig { const BIT_ORDER: u32 = 1 << 0; @@ -630,23 +549,10 @@ pub enum Interrupt { } /// Interrupt state register. -#[allow(non_camel_case_types)] -#[repr(transparent)] -pub struct INTERRUPT_STATE(UnsafeCell); - -/// Interrupt state. #[derive(Clone, Copy, Debug, PartialEq, Eq, Default)] #[repr(transparent)] pub struct InterruptState(u32); -impl INTERRUPT_STATE { - /// Read interrupt state. - #[inline] - pub fn read(&self) -> InterruptState { - InterruptState(unsafe { self.0.get().read_volatile() }) - } -} - impl InterruptState { /// Check if has interrupt. #[inline] @@ -656,28 +562,10 @@ impl InterruptState { } /// Interrupt mask register. -#[allow(non_camel_case_types)] -#[repr(transparent)] -pub struct INTERRUPT_MASK(UnsafeCell); - -/// Interrupt mask. #[derive(Clone, Copy, Debug, PartialEq, Eq, Default)] #[repr(transparent)] pub struct InterruptMask(u32); -impl INTERRUPT_MASK { - /// Read interrupt mask. - #[inline] - pub fn read(&self) -> InterruptMask { - InterruptMask(unsafe { self.0.get().read_volatile() }) - } - /// Write interrupt mask. - #[inline] - pub fn write(&self, val: InterruptMask) { - unsafe { self.0.get().write_volatile(val.0) } - } -} - impl InterruptMask { /// Set interrupt mask. #[inline] @@ -697,23 +585,10 @@ impl InterruptMask { } /// Interrupt clear register. -#[allow(non_camel_case_types)] -#[repr(transparent)] -pub struct INTERRUPT_CLEAR(UnsafeCell); - -/// Interrupt clear. #[derive(Clone, Copy, Debug, PartialEq, Eq, Default)] #[repr(transparent)] pub struct InterruptClear(u32); -impl INTERRUPT_CLEAR { - /// Write interrupt clear. - #[inline] - pub fn write(&self, val: InterruptClear) { - unsafe { self.0.get().write_volatile(val.0) } - } -} - impl InterruptClear { /// Clear interrupt. #[inline] @@ -723,28 +598,10 @@ impl InterruptClear { } /// Interrupt enable register. -#[allow(non_camel_case_types)] -#[repr(transparent)] -pub struct INTERRUPT_ENABLE(UnsafeCell); - -/// Interrupt enable. #[derive(Clone, Copy, Debug, PartialEq, Eq, Default)] #[repr(transparent)] pub struct InterruptEnable(u32); -impl INTERRUPT_ENABLE { - /// Read interrupt enable. - #[inline] - pub fn read(&self) -> InterruptEnable { - InterruptEnable(unsafe { self.0.get().read_volatile() }) - } - /// Write interrupt enable. - #[inline] - pub fn write(&self, val: InterruptEnable) { - unsafe { self.0.get().write_volatile(val.0) } - } -} - impl InterruptEnable { /// Enable interrupt. #[inline] @@ -764,28 +621,10 @@ impl InterruptEnable { } /// Bus state register. -#[allow(non_camel_case_types)] -#[repr(transparent)] -pub struct BUS_STATE(UnsafeCell); - -/// Configuration structure for bus state. #[derive(Clone, Copy, Debug, PartialEq, Eq, Default)] #[repr(transparent)] pub struct BusState(u32); -impl BUS_STATE { - /// Read bus state. - #[inline] - pub fn read(&self) -> BusState { - BusState(unsafe { self.0.get().read_volatile() }) - } - /// Write bus state. - #[inline] - pub fn write(&self, val: BusState) { - unsafe { self.0.get().write_volatile(val.0) } - } -} - impl BusState { const TRANSMIT_BUSY: u32 = 1 << 0; const RECEIVE_BUSY: u32 = 1 << 1; @@ -803,28 +642,10 @@ impl BusState { } /// First-in first-out queue configuration 0. -#[allow(non_camel_case_types)] -#[repr(transparent)] -pub struct FIFO_CONFIG_0(UnsafeCell); - -/// Configuration structure for first-in first-out queue register 0. #[derive(Clone, Copy, Debug, PartialEq, Eq, Default)] #[repr(transparent)] pub struct FifoConfig0(u32); -impl FIFO_CONFIG_0 { - /// Read first-in first-out queue configuration register 0. - #[inline] - pub fn read(&self) -> FifoConfig0 { - FifoConfig0(unsafe { self.0.get().read_volatile() }) - } - /// Write first-in first-out queue configuration register 0. - #[inline] - pub fn write(&self, val: FifoConfig0) { - unsafe { self.0.get().write_volatile(val.0) } - } -} - impl FifoConfig0 { const TRANSMIT_DMA_ENABLE: u32 = 1 << 0; const RECEIVE_DMA_ENABLE: u32 = 1 << 1; @@ -898,28 +719,10 @@ impl FifoConfig0 { } /// First-in first-out queue configuration 1. -#[allow(non_camel_case_types)] -#[repr(transparent)] -pub struct FIFO_CONFIG_1(UnsafeCell); - -/// Configuration structure for first-in first-out queue register 1. #[derive(Clone, Copy, Debug, PartialEq, Eq, Default)] #[repr(transparent)] pub struct FifoConfig1(u32); -impl FIFO_CONFIG_1 { - /// Read first-in first-out queue configuration register 1. - #[inline] - pub fn read(&self) -> FifoConfig1 { - FifoConfig1(unsafe { self.0.get().read_volatile() }) - } - /// Write first-in first-out queue configuration register 1. - #[inline] - pub fn write(&self, val: FifoConfig1) { - unsafe { self.0.get().write_volatile(val.0) } - } -} - impl FifoConfig1 { const TRANSMIT_COUNT: u32 = 0x3f; const RECEIVE_COUNT: u32 = 0x3f << 8; @@ -1322,7 +1125,7 @@ pub struct DataRead(u8); impl DATA_READ { /// Read a byte from first-in first-out queue. #[inline] - pub fn read_u8(self) -> u8 { + pub fn read_u8(&self) -> u8 { unsafe { self.0.get().read_volatile() } } } @@ -1368,13 +1171,13 @@ impl Serial { let val = BitPeriod(0) .set_transmit_time_interval(interval as u16) .set_receive_time_interval(interval as u16); - uart.bit_period.write(val); + unsafe { uart.bit_period.write(val) }; // Write bit order let val = DataConfig(0).set_bit_order(config.bit_order); - uart.data_config.write(val); + unsafe { uart.data_config.write(val) }; - // Config transmit + // Configure transmit feature let mut val = TransmitConfig(0) .enable_freerun() .set_parity(config.parity) @@ -1386,7 +1189,16 @@ impl Serial { if PINS::CTS { val = val.enable_cts(); } - uart.transmit_config.write(val); + unsafe { uart.transmit_config.write(val) }; + + // Configure receive feature + let mut val = ReceiveConfig(0) + .set_parity(config.parity) + .set_word_length(config.word_length); + if PINS::RXD { + val = val.enable_rxd(); + } + unsafe { uart.receive_config.write(val) }; Self { uart, pins } } @@ -1481,6 +1293,23 @@ impl embedded_io::blocking::Write for Serial { } } +impl embedded_io::blocking::Read for Serial { + #[inline] + fn read(&mut self, buf: &mut [u8]) -> Result { + while self.uart.fifo_config_1.read().receive_available_bytes() == 0 { + core::hint::spin_loop(); + } + let len = core::cmp::min( + self.uart.fifo_config_1.read().receive_available_bytes() as usize, + buf.len(), + ); + for i in 0..len { + buf[i] = self.uart.data_read.read_u8(); + } + Ok(len) + } +} + #[cfg(feature = "glb-v2")] const UART_GPIO_CONFIG: GpioConfig = GpioConfig::RESET_VALUE .enable_input()