From 199a025d3fdc935aa255218f25e9e433071ce7bf Mon Sep 17 00:00:00 2001 From: Zhouqi Jiang Date: Sun, 23 Jul 2023 22:55:34 +0800 Subject: [PATCH 1/2] =?UTF-8?q?uart:=20=E6=B7=BB=E5=8A=A0=E4=B8=B2?= =?UTF-8?q?=E5=8F=A3=E6=8E=A5=E6=94=B6=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 修改embedded-io示例为控制台示例。 Signed-off-by: Zhouqi Jiang --- examples/uart-embedded-io/src/main.rs | 52 +++++++++++++++++++-------- src/uart.rs | 41 ++++++++++++++------- 2 files changed, 65 insertions(+), 28 deletions(-) diff --git a/examples/uart-embedded-io/src/main.rs b/examples/uart-embedded-io/src/main.rs index a29809b..99dc6dc 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 5700a7b..899d7b3 100644 --- a/src/uart.rs +++ b/src/uart.rs @@ -336,7 +336,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 +470,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 { @@ -1322,7 +1311,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() } } } @@ -1374,7 +1363,7 @@ impl Serial { let val = DataConfig(0).set_bit_order(config.bit_order); uart.data_config.write(val); - // Config transmit + // Configure transmit feature let mut val = TransmitConfig(0) .enable_freerun() .set_parity(config.parity) @@ -1388,6 +1377,15 @@ impl Serial { } 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(); + } + uart.receive_config.write(val); + Self { uart, pins } } @@ -1481,6 +1479,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() -- Gitee From dee479e3f63703b61f82099c14b8ad00bbde2b46 Mon Sep 17 00:00:00 2001 From: Zhouqi Jiang Date: Sun, 23 Jul 2023 23:11:36 +0800 Subject: [PATCH 2/2] =?UTF-8?q?uart:=20=E4=BD=BF=E7=94=A8volatile-register?= =?UTF-8?q?=E7=BB=93=E6=9E=84=E4=BD=93=E8=A1=A8=E7=A4=BA=E5=A4=96=E8=AE=BE?= =?UTF-8?q?=E5=AF=84=E5=AD=98=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 包括RO、RW和WO,使文档更精简,增加可读性。 Signed-off-by: Zhouqi Jiang --- src/uart.rs | 218 ++++------------------------------------------------ 1 file changed, 16 insertions(+), 202 deletions(-) diff --git a/src/uart.rs b/src/uart.rs index 899d7b3..99764f9 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; @@ -508,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); @@ -556,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; @@ -619,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] @@ -645,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] @@ -686,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] @@ -712,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] @@ -753,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; @@ -792,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; @@ -887,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; @@ -1357,11 +1171,11 @@ 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) }; // Configure transmit feature let mut val = TransmitConfig(0) @@ -1375,7 +1189,7 @@ 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) @@ -1384,7 +1198,7 @@ impl Serial { if PINS::RXD { val = val.enable_rxd(); } - uart.receive_config.write(val); + unsafe { uart.receive_config.write(val) }; Self { uart, pins } } -- Gitee