From a8b484d66f31b1b540d5d131da17b8f7b968300b Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Sun, 19 Dec 2021 15:45:46 +0100 Subject: [PATCH] UART reception and echo reply now working - Important bugfix in UART: use `modify` instead of `write` when enabling or disabling TX or RX - Extend RTIC example application. Reply handling is dispatched to lower priority interrupt --- Cargo.toml | 1 + examples/cascade.rs | 2 +- examples/uart-irq-rtic.rs | 121 ++++++++--- src/uart.rs | 414 ++++++++++++++++++++++++++++++-------- 4 files changed, 423 insertions(+), 115 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index e295305..b47a53b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,6 +28,7 @@ rt = ["va108xx/rt"] [dev-dependencies] cortex-m-rtic = "0.6.0-rc.4" +arrayvec = { version = "0.7.2", default-features = false } panic-rtt-target = { version = "0.1", features = ["cortex-m"] } rtt-target = { version = "0.3", features = ["cortex-m"] } panic-halt = "0.2" diff --git a/examples/cascade.rs b/examples/cascade.rs index 03e5c09..3b1c363 100644 --- a/examples/cascade.rs +++ b/examples/cascade.rs @@ -11,7 +11,7 @@ use cortex_m_rt::entry; use panic_rtt_target as _; use rtt_target::{rprintln, rtt_init_print}; use va108xx_hal::{ - pac::{self, Interrupt, TIM4, TIM5}, + pac::{self, interrupt, TIM4, TIM5}, prelude::*, timer::{ default_ms_irq_handler, set_up_ms_delay_provider, CascadeCtrl, CascadeSource, diff --git a/examples/uart-irq-rtic.rs b/examples/uart-irq-rtic.rs index b46133e..cf16b7a 100644 --- a/examples/uart-irq-rtic.rs +++ b/examples/uart-irq-rtic.rs @@ -3,40 +3,52 @@ #![no_main] #![no_std] -#[rtic::app(device = pac)] +#[rtic::app(device = pac, dispatchers = [OC4])] mod app { use core::fmt::Write; use panic_rtt_target as _; - use rtt_target::{rprintln, rtt_init_print}; - use va108xx_hal::{gpio::PinsB, pac, prelude::*, uart}; + use rtt_target::{rprintln, rtt_init_default, set_print_channel}; + use va108xx_hal::{ + gpio::PinsB, + pac, + prelude::*, + uart::{self, IrqCfg, IrqResult, UartWithIrqBase}, + }; #[local] struct Local {} #[shared] - struct Shared {} + struct Shared { + irq_uart: UartWithIrqBase, + rx_buf: [u8; 64], + } #[init] - fn init(_ctx: init::Context) -> (Shared, Local, init::Monotonics) { - rtt_init_print!(); - rprintln!("-- VA108xx UART example application--"); - - let mut dp = pac::Peripherals::take().unwrap(); - + fn init(ctx: init::Context) -> (Shared, Local, init::Monotonics) { + let channels = rtt_init_default!(); + set_print_channel(channels.up.0); + rprintln!("-- VA108xx UART IRQ example application--"); + let mut dp = ctx.device; let gpiob = PinsB::new(&mut dp.SYSCONFIG, Some(dp.IOCONFIG), dp.PORTB); let tx = gpiob.pb21.into_funsel_1(); let rx = gpiob.pb20.into_funsel_1(); - - let uartb = uart::Uart::uartb( + + let irq_cfg = IrqCfg::new(pac::interrupt::OC3, true, true); + let (mut irq_uart, _) = uart::Uart::uartb( dp.UARTB, (tx, rx), 115200.bps(), &mut dp.SYSCONFIG, 50.mhz(), - ); - let (mut tx, mut _rx) = uartb.split(); - writeln!(tx, "Hello World\r").unwrap(); - (Shared {}, Local {}, init::Monotonics()) + ) + .into_uart_with_irq(irq_cfg, Some(&mut dp.SYSCONFIG), Some(&mut dp.IRQSEL)) + .downgrade(); + irq_uart + .read_fixed_len_using_irq(64, true) + .expect("Read initialization failed"); + let rx_buf: [u8; 64] = [0; 64]; + (Shared { irq_uart, rx_buf }, Local {}, init::Monotonics()) } // `shared` cannot be accessed from this context @@ -44,21 +56,64 @@ mod app { fn idle(_cx: idle::Context) -> ! { loop {} } + + #[task( + binds = OC3, + shared = [irq_uart, rx_buf], + local = [cnt: u32 = 0, result: IrqResult = IrqResult::new()], + priority = 4 + )] + fn reception_task(cx: reception_task::Context) { + let result = cx.local.result; + let cnt: &mut u32 = cx.local.cnt; + let irq_uart = cx.shared.irq_uart; + let rx_buf = cx.shared.rx_buf; + let (completed, end_idx) = (irq_uart, rx_buf).lock(|irq_uart, rx_buf| { + match irq_uart.irq_handler(result, rx_buf) { + Ok(_) => { + if result.complete() { + // Initiate next transfer immediately + irq_uart + .read_fixed_len_using_irq(64, true) + .expect("Read operation init failed"); + + let mut end_idx = 0; + for idx in 0..rx_buf.len() { + if (rx_buf[idx] as char) == '\n' { + end_idx = idx; + break; + } + } + (true, end_idx) + } else { + (false, 0) + } + } + Err(e) => { + rprintln!("Reception Error {:?}", e); + (false, 0) + } + } + }); + if completed { + rprintln!("Counter: {}", cnt); + reply_handler::spawn(result.bytes_read, end_idx, result.timeout()).unwrap(); + } + *cnt += 1; + } + + #[task(shared = [irq_uart, rx_buf], priority = 3)] + fn reply_handler(cx: reply_handler::Context, bytes_read: usize, end_idx: usize, timeout: bool) { + let irq_uart = cx.shared.irq_uart; + let rx_buf = cx.shared.rx_buf; + (irq_uart, rx_buf).lock(|irq_uart, rx_buf| { + rprintln!("Reception success, {} bytes read", bytes_read); + if timeout { + rprintln!("Timeout occured"); + } + let string = core::str::from_utf8(&rx_buf[0..end_idx]).expect("Invalid string format"); + rprintln!("Read string: {}", string); + writeln!(irq_uart.uart, "{}", string).expect("Sending reply failed"); + }); + } } - -// #[entry] -// fn main() -> ! { - -// loop { -// // Echo what is received on the serial link. -// match rx.read() { -// Ok(recv) => { -// nb::block!(tx.write(recv)).expect("TX send error"); -// } -// Err(nb::Error::WouldBlock) => (), -// Err(nb::Error::Other(uart_error)) => { -// rprintln!("UART receive error {:?}", uart_error); -// } -// } -// } -// } diff --git a/src/uart.rs b/src/uart.rs index 6882418..1644976 100644 --- a/src/uart.rs +++ b/src/uart.rs @@ -7,10 +7,9 @@ use core::{convert::Infallible, ptr}; use core::{marker::PhantomData, ops::Deref}; use libm::floorf; -use crate::clock::enable_peripheral_clock; pub use crate::utility::IrqCfg; use crate::{ - clock, + clock::{self, enable_peripheral_clock, PeripheralClocks}, gpio::pins::{ AltFunc1, AltFunc2, AltFunc3, Pin, PA16, PA17, PA18, PA19, PA2, PA26, PA27, PA3, PA30, PA31, PA8, PA9, PB18, PB19, PB20, PB21, PB22, PB23, PB6, PB7, PB8, PB9, @@ -56,6 +55,8 @@ pub enum Error { BreakCondition, TransferPending, BufferTooShort, + /// Can be a combination of overrun, framing or parity error + IrqError, } #[derive(Debug, PartialEq, Copy, Clone)] @@ -191,12 +192,25 @@ pub enum IrqResultMask { Break = 4, Timeout = 5, Addr9 = 6, + /// Should not happen + Unknown = 7, } + +#[derive(Debug, Default)] pub struct IrqResult { raw_res: u32, pub bytes_read: usize, } +impl IrqResult { + pub const fn new() -> Self { + IrqResult { + raw_res: 0, + bytes_read: 0, + } + } +} + impl IrqResult { #[inline] pub fn raw_result(&self) -> u32 { @@ -214,7 +228,7 @@ impl IrqResult { #[inline] pub fn complete(&self) -> bool { - if ((self.raw_res >> IrqResultMask::Complete as u32) & 0x01) == 0x00 { + if ((self.raw_res >> IrqResultMask::Complete as u32) & 0x01) == 0x01 { return true; } false @@ -272,16 +286,24 @@ pub enum IrqReceptionMode { // UART implementation //================================================================================================== -/// Serial abstraction -pub struct Uart { +pub struct UartBase { uart: UART, - pins: PINS, tx: Tx, rx: Rx, } +/// Serial abstraction +pub struct Uart { + uart_base: UartBase, + pins: PINS, +} pub struct UartWithIrq { - uart_base: Uart, + irq_base: UartWithIrqBase, + pins: PINS, +} + +pub struct UartWithIrqBase { + pub uart: UartBase, irq_info: IrqInfo, } @@ -313,12 +335,10 @@ impl Tx { pub trait Instance: Deref { fn ptr() -> *const uart_base::RegisterBlock; + const IDX: u8; } -impl Uart -where - UART: Instance, -{ +impl UartBase { /// This function assumes that the peripheral clock was alredy enabled /// in the SYSCONFIG register fn init(self, config: Config, sys_clk: Hertz) -> Self { @@ -366,22 +386,22 @@ where #[inline] pub fn enable_rx(&mut self) { - self.uart.enable.write(|w| w.rxenable().set_bit()); + self.uart.enable.modify(|_, w| w.rxenable().set_bit()); } #[inline] pub fn disable_rx(&mut self) { - self.uart.enable.write(|w| w.rxenable().set_bit()); + self.uart.enable.modify(|_, w| w.rxenable().clear_bit()); } #[inline] pub fn enable_tx(&mut self) { - self.uart.enable.write(|w| w.txenable().set_bit()); + self.uart.enable.modify(|_, w| w.txenable().set_bit()); } #[inline] pub fn disable_tx(&mut self) { - self.uart.enable.write(|w| w.txenable().set_bit()); + self.uart.enable.modify(|_, w| w.txenable().clear_bit()); } #[inline] @@ -404,7 +424,7 @@ where self.uart.fifo_clr.write(|w| w.txsts().set_bit()); } - pub fn listen(self, event: Event) -> Self { + pub fn listen(&self, event: Event) { self.uart.irq_enb.modify(|_, w| match event { Event::RxError => w.irq_rx_status().set_bit(), Event::RxFifoHalfFull => w.irq_rx().set_bit(), @@ -414,10 +434,9 @@ where Event::TxFifoHalfFull => w.irq_tx().set_bit(), Event::TxCts => w.irq_tx_cts().set_bit(), }); - self } - pub fn unlisten(self, event: Event) -> Self { + pub fn unlisten(&self, event: Event) { self.uart.irq_enb.modify(|_, w| match event { Event::RxError => w.irq_rx_status().clear_bit(), Event::RxFifoHalfFull => w.irq_rx().clear_bit(), @@ -427,10 +446,9 @@ where Event::TxFifoHalfFull => w.irq_tx().clear_bit(), Event::TxCts => w.irq_tx_cts().clear_bit(), }); - self } - pub fn release(self) -> (UART, PINS) { + pub fn release(self) -> UART { // Clear the FIFO self.uart.fifo_clr.write(|w| { w.rxfifo().set_bit(); @@ -440,7 +458,7 @@ where w.rxenable().clear_bit(); w.txenable().clear_bit() }); - (self.uart, self.pins) + self.uart } pub fn split(self) -> (Tx, Rx) { @@ -448,14 +466,130 @@ where } } +impl Uart +where + UART: Instance, +{ + /// This function assumes that the peripheral clock was alredy enabled + /// in the SYSCONFIG register + fn init(mut self, config: Config, sys_clk: Hertz) -> Self { + self.uart_base = self.uart_base.init(config, sys_clk); + self + } + + pub fn into_uart_with_irq( + self, + irq_cfg: IrqCfg, + sys_cfg: Option<&mut SYSCONFIG>, + irq_sel: Option<&mut IRQSEL>, + ) -> UartWithIrq { + let (uart, pins) = self.downgrade_internal(); + UartWithIrq { + pins, + irq_base: UartWithIrqBase { + uart, + irq_info: IrqInfo { + rx_len: 0, + rx_idx: 0, + irq_cfg, + mode: IrqReceptionMode::Idle, + }, + } + .init(sys_cfg, irq_sel), + } + } + + #[inline] + pub fn enable_rx(&mut self) { + self.uart_base.enable_rx(); + } + + #[inline] + pub fn disable_rx(&mut self) { + self.uart_base.enable_rx(); + } + + #[inline] + pub fn enable_tx(&mut self) { + self.uart_base.enable_tx(); + } + + #[inline] + pub fn disable_tx(&mut self) { + self.uart_base.disable_tx(); + } + + #[inline] + pub fn clear_rx_fifo(&mut self) { + self.uart_base.clear_rx_fifo(); + } + + #[inline] + pub fn clear_tx_fifo(&mut self) { + self.uart_base.clear_tx_fifo(); + } + + #[inline] + pub fn clear_rx_status(&mut self) { + self.uart_base.clear_rx_status(); + } + + #[inline] + pub fn clear_tx_status(&mut self) { + self.uart_base.clear_tx_status(); + } + + pub fn listen(&self, event: Event) { + self.uart_base.listen(event); + } + + pub fn unlisten(&self, event: Event) { + self.uart_base.unlisten(event); + } + + pub fn release(self) -> (UART, PINS) { + (self.uart_base.release(), self.pins) + } + + fn downgrade_internal(self) -> (UartBase, PINS) { + let base = UartBase { + uart: self.uart_base.uart, + tx: self.uart_base.tx, + rx: self.uart_base.rx, + }; + (base, self.pins) + } + + pub fn downgrade(self) -> UartBase { + UartBase { + uart: self.uart_base.uart, + tx: self.uart_base.tx, + rx: self.uart_base.rx, + } + } + + pub fn split(self) -> (Tx, Rx) { + self.uart_base.split() + } +} + +impl Instance for UARTA { + fn ptr() -> *const uart_base::RegisterBlock { + UARTA::ptr() as *const _ + } + const IDX: u8 = 0; +} + +impl Instance for UARTB { + fn ptr() -> *const uart_base::RegisterBlock { + UARTB::ptr() as *const _ + } + const IDX: u8 = 1; +} + macro_rules! uart_impl { ($($UARTX:ident: ($uartx:ident, $clk_enb_enum:path),)+) => { $( - impl Instance for $UARTX { - fn ptr() -> *const uart_base::RegisterBlock { - $UARTX::ptr() as *const _ - } - } impl> Uart<$UARTX, PINS> { pub fn $uartx( @@ -467,47 +601,49 @@ macro_rules! uart_impl { ) -> Self { enable_peripheral_clock(syscfg, $clk_enb_enum); - Uart { uart, pins, tx: Tx::new(), rx: Rx::new() }.init( - config.into(), sys_clk.into() - ) + Uart { + uart_base: UartBase { + uart, + tx: Tx::new(), + rx: Rx::new(), + }, + pins, + } + .init(config.into(), sys_clk.into()) } } + )+ } } -impl Uart { - pub fn into_uart_with_irq(self, irq_cfg: IrqCfg) -> UartWithIrq { - UartWithIrq { - uart_base: self, - irq_info: IrqInfo { - rx_len: 0, - rx_idx: 0, - irq_cfg, - mode: IrqReceptionMode::Idle, - }, +impl UartWithIrqBase { + fn init(self, sys_cfg: Option<&mut SYSCONFIG>, irq_sel: Option<&mut IRQSEL>) -> Self { + if let Some(sys_cfg) = sys_cfg { + enable_peripheral_clock(sys_cfg, PeripheralClocks::Irqsel) } + if let Some(irq_sel) = irq_sel { + if self.irq_info.irq_cfg.route { + irq_sel.uart[UART::IDX as usize] + .write(|w| unsafe { w.bits(self.irq_info.irq_cfg.irq as u32) }); + } + } + self } -} -impl UartWithIrq { pub fn read_fixed_len_using_irq( &mut self, max_len: usize, enb_timeout_irq: bool, - irqsel: Option<&mut IRQSEL>, ) -> Result<(), Error> { if self.irq_info.mode != IrqReceptionMode::Idle { return Err(Error::TransferPending); } self.irq_info.rx_idx = 0; self.irq_info.rx_len = max_len; + self.uart.enable_rx(); + self.uart.enable_tx(); self.enable_rx_irq_sources(enb_timeout_irq); - if let Some(irqsel) = irqsel { - if self.irq_info.irq_cfg.route { - irqsel.uart[0].write(|w| unsafe { w.bits(self.irq_info.irq_cfg.irq as u32) }); - } - } if self.irq_info.irq_cfg.enable { unmask_irq(self.irq_info.irq_cfg.irq); } @@ -516,7 +652,7 @@ impl UartWithIrq { #[inline] fn enable_rx_irq_sources(&mut self, timeout: bool) { - self.uart_base.uart.irq_enb.modify(|_, w| { + self.uart.uart.irq_enb.modify(|_, w| { if timeout { w.irq_rx_to().set_bit(); } @@ -527,18 +663,28 @@ impl UartWithIrq { #[inline] fn disable_rx_irq_sources(&mut self) { - self.uart_base.uart.irq_enb.modify(|_, w| { + self.uart.uart.irq_enb.modify(|_, w| { w.irq_rx_to().clear_bit(); w.irq_rx_status().clear_bit(); w.irq_rx().clear_bit() }); } + #[inline] + pub fn enable_tx(&mut self) { + self.uart.enable_tx() + } + + #[inline] + pub fn disable_tx(&mut self) { + self.uart.disable_tx() + } + pub fn cancel_transfer(&mut self) { // Disable IRQ cortex_m::peripheral::NVIC::mask(self.irq_info.irq_cfg.irq); self.disable_rx_irq_sources(); - self.uart_base.clear_tx_fifo(); + self.uart.clear_tx_fifo(); self.irq_info.rx_idx = 0; self.irq_info.rx_len = 0; } @@ -548,36 +694,68 @@ impl UartWithIrq { return Err(Error::BufferTooShort); } - let mut rx_status = self.uart_base.uart.rxstatus.read(); - let _tx_status = self.uart_base.uart.txstatus.read(); - let irq_end = self.uart_base.uart.irq_end.read(); - - let enb_status = self.uart_base.uart.enable.read(); + let irq_end = self.uart.uart.irq_end.read(); + let enb_status = self.uart.uart.enable.read(); let rx_enabled = enb_status.rxenable().bit_is_set(); let _tx_enabled = enb_status.txenable().bit_is_set(); - res.clear_result(); - if irq_end.irq_rx().bit_is_set() && rx_status.rdavl().bit_is_set() { - let mut rd_avl = rx_status.rdavl(); - // While there is data in the FIFO, write it into the reception buffer - while self.irq_info.rx_idx < self.irq_info.rx_len && rd_avl.bit_is_set() { - buf[self.irq_info.rx_idx] = nb::block!(self.uart_base.read()).unwrap(); - rd_avl = self.uart_base.uart.rxstatus.read().rdavl(); + let read_handler = + |res: &mut IrqResult, read_res: nb::Result| -> Result, Error> { + match read_res { + Ok(byte) => return Ok(Some(byte)), + Err(nb::Error::WouldBlock) => { + return Ok(None); + } + Err(nb::Error::Other(e)) => match e { + Error::Overrun => { + res.set_result(IrqResultMask::Overflow); + return Err(Error::IrqError); + } + Error::FramingError => { + res.set_result(IrqResultMask::FramingError); + return Err(Error::IrqError); + } + Error::ParityError => { + res.set_result(IrqResultMask::ParityError); + return Err(Error::IrqError); + } + _ => { + res.set_result(IrqResultMask::Unknown); + return Err(Error::IrqError); + } + }, + }; + }; + if irq_end.irq_rx().bit_is_set() { + // If this interrupt bit is set, the trigger level is available at the very least. + // Read everything as fast as possible + for _ in 0..core::cmp::min( + self.uart.uart.rxfifoirqtrg.read().bits() as usize, + self.irq_info.rx_len, + ) { + buf[self.irq_info.rx_idx] = (self.uart.uart.data.read().bits() & 0xff) as u8; self.irq_info.rx_idx += 1; + } + + // While there is data in the FIFO, write it into the reception buffer + loop { if self.irq_info.rx_idx == self.irq_info.rx_len { - self.disable_rx_irq_sources(); - res.bytes_read = self.irq_info.rx_len; - res.set_result(IrqResultMask::Complete); - self.irq_info.rx_idx = 0; - self.irq_info.rx_len = 0; + self.irq_completion_handler(res); return Ok(()); } + if let Some(byte) = read_handler(res, self.uart.read())? { + buf[self.irq_info.rx_idx] = byte; + self.irq_info.rx_idx += 1; + } else { + break; + } } } // RX transfer not complete, check for RX errors if (self.irq_info.rx_idx < self.irq_info.rx_len) && rx_enabled { // Read status register again, might have changed since reading received data - rx_status = self.uart_base.uart.rxstatus.read(); + let rx_status = self.uart.uart.rxstatus.read(); + res.clear_result(); if rx_status.rxovr().bit_is_set() { res.set_result(IrqResultMask::Overflow); } @@ -593,27 +771,74 @@ impl UartWithIrq { if rx_status.rxto().bit_is_set() { // A timeout has occured but there might be some leftover data in the FIFO, // so read that data as well - while self.irq_info.rx_idx < self.irq_info.rx_len && rx_status.rdavl().bit_is_set() - { - buf[self.irq_info.rx_idx] = nb::block!(self.uart_base.read()).unwrap(); - self.irq_info.rx_idx += 1; + loop { + if let Some(byte) = read_handler(res, self.uart.read())? { + buf[self.irq_info.rx_idx] = byte; + self.irq_info.rx_idx += 1; + } else { + break; + } } - res.bytes_read = self.irq_info.rx_idx; + self.irq_completion_handler(res); res.set_result(IrqResultMask::Timeout); - res.set_result(IrqResultMask::Complete); + return Ok(()); } + // If it is not a timeout, it's an error if res.raw_res != 0 { self.disable_rx_irq_sources(); + return Err(Error::IrqError); } } - self.uart_base + // Clear the interrupt status bits + self.uart .uart .irq_clr .write(|w| unsafe { w.bits(irq_end.bits()) }); Ok(()) } + + fn irq_completion_handler(&mut self, res: &mut IrqResult) { + self.disable_rx_irq_sources(); + self.uart.disable_rx(); + res.bytes_read = self.irq_info.rx_idx; + res.clear_result(); + res.set_result(IrqResultMask::Complete); + self.irq_info.rx_idx = 0; + self.irq_info.rx_len = 0; + } + + pub fn release(self) -> UART { + self.uart.release() + } +} + +impl UartWithIrq { + pub fn read_fixed_len_using_irq( + &mut self, + max_len: usize, + enb_timeout_irq: bool, + ) -> Result<(), Error> { + self.irq_base + .read_fixed_len_using_irq(max_len, enb_timeout_irq) + } + + pub fn cancel_transfer(&mut self) { + self.irq_base.cancel_transfer() + } + + pub fn irq_handler(&mut self, res: &mut IrqResult, buf: &mut [u8]) -> Result<(), Error> { + self.irq_base.irq_handler(res, buf) + } + + pub fn release(self) -> (UART, PINS) { + (self.irq_base.release(), self.pins) + } + + pub fn downgrade(self) -> (UartWithIrqBase, PINS) { + (self.irq_base, self.pins) + } } uart_impl! { @@ -623,10 +848,7 @@ uart_impl! { impl Tx where UART: Instance {} -impl serial::Write for Uart -where - UART: Instance, -{ +impl serial::Write for UartBase { type Error = Infallible; fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> { self.tx.write(word) @@ -636,6 +858,19 @@ where } } +impl serial::Write for Uart +where + UART: Instance, +{ + type Error = Infallible; + fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> { + self.uart_base.write(word) + } + fn flush(&mut self) -> nb::Result<(), Self::Error> { + self.uart_base.flush() + } +} + impl blocking::serial::write::Default for Uart {} impl serial::Write for Tx { @@ -667,7 +902,7 @@ impl serial::Write for Tx { } } -impl serial::Read for Uart { +impl serial::Read for UartBase { type Error = Error; fn read(&mut self) -> nb::Result { @@ -675,6 +910,14 @@ impl serial::Read for Uart { } } +impl serial::Read for Uart { + type Error = Error; + + fn read(&mut self) -> nb::Result { + self.uart_base.read() + } +} + impl serial::Read for Rx { type Error = Error; @@ -706,7 +949,7 @@ impl serial::Read for Rx { } } -impl core::fmt::Write for Tx +impl core::fmt::Write for Tx where Tx: embedded_hal::serial::Write, { @@ -717,3 +960,12 @@ where .map_err(|_| core::fmt::Error) } } + +impl core::fmt::Write for UartBase +where + UartBase: embedded_hal::serial::Write, +{ + fn write_str(&mut self, s: &str) -> core::fmt::Result { + self.tx.write_str(s) + } +}