From 48e737fe385d8deb209ffcaec0da50da7bc2c4ff Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Sun, 15 May 2022 05:35:22 +0200 Subject: [PATCH 1/4] Store `Tx` and `Rx` in `Serial`. --- src/serial.rs | 80 ++++++++++++++++++++++----------------------------- 1 file changed, 35 insertions(+), 45 deletions(-) diff --git a/src/serial.rs b/src/serial.rs index 2e36c7b4..493d9ec5 100644 --- a/src/serial.rs +++ b/src/serial.rs @@ -208,6 +208,8 @@ impl From for Config { pub struct Serial { usart: USART, pins: PINS, + tx: Tx, + rx: Rx, } /// Serial receiver @@ -372,7 +374,11 @@ macro_rules! hal { .cr1 .modify(|_, w| w.ue().set_bit().re().set_bit().te().set_bit()); - Serial { usart, pins } + Serial { + usart, pins, + tx: Tx { _usart: PhantomData }, + rx: Rx { _usart: PhantomData }, + } } /// Starts listening for an interrupt event @@ -400,10 +406,28 @@ macro_rules! hal { /// /// See [`Rx::check_for_error`]. pub fn check_for_error() -> Result<(), Error> { - let mut rx: Rx = Rx { - _usart: PhantomData, - }; - rx.check_for_error() + // NOTE(unsafe): Only used for atomic access. + let isr = unsafe { (*pac::$USARTX::ptr()).isr.read() }; + let icr = unsafe { &(*pac::$USARTX::ptr()).icr }; + + if isr.pe().bit_is_set() { + icr.write(|w| w.pecf().clear()); + return Err(Error::Parity); + } + if isr.fe().bit_is_set() { + icr.write(|w| w.fecf().clear()); + return Err(Error::Framing); + } + if isr.nf().bit_is_set() { + icr.write(|w| w.ncf().clear()); + return Err(Error::Noise); + } + if isr.ore().bit_is_set() { + icr.write(|w| w.orecf().clear()); + return Err(Error::Overrun); + } + + Ok(()) } /// Stops listening for an interrupt event @@ -430,12 +454,8 @@ macro_rules! hal { /// Splits the `Serial` abstraction into a transmitter and a receiver half pub fn split(self) -> (Tx, Rx) { ( - Tx { - _usart: PhantomData, - }, - Rx { - _usart: PhantomData, - }, + self.tx, + self.rx, ) } @@ -449,10 +469,7 @@ macro_rules! hal { type Error = Error; fn read(&mut self) -> nb::Result { - let mut rx: Rx = Rx { - _usart: PhantomData, - }; - rx.read() + self.rx.read() } } @@ -480,17 +497,11 @@ macro_rules! hal { type Error = Error; fn flush(&mut self) -> nb::Result<(), Error> { - let mut tx: Tx = Tx { - _usart: PhantomData, - }; - tx.flush() + self.tx.flush() } fn write(&mut self, byte: u8) -> nb::Result<(), Error> { - let mut tx: Tx = Tx { - _usart: PhantomData, - }; - tx.write(byte) + self.tx.write(byte) } } @@ -579,28 +590,7 @@ macro_rules! hal { /// `Ok(())`, it should be possible to proceed with the next /// `read` call unimpeded. pub fn check_for_error(&mut self) -> Result<(), Error> { - // NOTE(unsafe): Only used for atomic access. - let isr = unsafe { (*pac::$USARTX::ptr()).isr.read() }; - let icr = unsafe { &(*pac::$USARTX::ptr()).icr }; - - if isr.pe().bit_is_set() { - icr.write(|w| w.pecf().clear()); - return Err(Error::Parity); - } - if isr.fe().bit_is_set() { - icr.write(|w| w.fecf().clear()); - return Err(Error::Framing); - } - if isr.nf().bit_is_set() { - icr.write(|w| w.ncf().clear()); - return Err(Error::Noise); - } - if isr.ore().bit_is_set() { - icr.write(|w| w.orecf().clear()); - return Err(Error::Overrun); - } - - Ok(()) + >::check_for_error() } /// Checks to see if the USART peripheral has detected an idle line and clears From beb1e56003a0bc71ae461a32bfd17c30cfaff8a1 Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Sun, 15 May 2022 06:11:45 +0200 Subject: [PATCH 2/4] Allow re-combining TX/RX pair to serial port. --- src/serial.rs | 106 +++++++++++++++++++++++++++----------------------- 1 file changed, 58 insertions(+), 48 deletions(-) diff --git a/src/serial.rs b/src/serial.rs index 493d9ec5..836ca582 100644 --- a/src/serial.rs +++ b/src/serial.rs @@ -206,20 +206,20 @@ impl From for Config { /// Serial abstraction pub struct Serial { - usart: USART, - pins: PINS, - tx: Tx, - rx: Rx, + tx: Tx, + rx: Rx, } /// Serial receiver -pub struct Rx { +pub struct Rx { _usart: PhantomData, + pins: PINS, } /// Serial transmitter -pub struct Tx { - _usart: PhantomData, +pub struct Tx { + usart: USART, + pins: PhantomData, } macro_rules! hal { @@ -375,29 +375,33 @@ macro_rules! hal { .modify(|_, w| w.ue().set_bit().re().set_bit().te().set_bit()); Serial { - usart, pins, - tx: Tx { _usart: PhantomData }, - rx: Rx { _usart: PhantomData }, + tx: Tx { usart, pins: PhantomData }, + rx: Rx { _usart: PhantomData, pins }, } } + #[inline] + fn usart(&self) -> &pac::$USARTX { + &self.tx.usart + } + /// Starts listening for an interrupt event pub fn listen(&mut self, event: Event) { match event { Event::Rxne => { - self.usart.cr1.modify(|_, w| w.rxneie().set_bit()) + self.usart().cr1.modify(|_, w| w.rxneie().set_bit()) }, Event::Txe => { - self.usart.cr1.modify(|_, w| w.txeie().set_bit()) + self.usart().cr1.modify(|_, w| w.txeie().set_bit()) }, Event::Idle => { - self.usart.cr1.modify(|_, w| w.idleie().set_bit()) + self.usart().cr1.modify(|_, w| w.idleie().set_bit()) }, Event::CharacterMatch => { - self.usart.cr1.modify(|_, w| w.cmie().set_bit()) + self.usart().cr1.modify(|_, w| w.cmie().set_bit()) }, Event::ReceiverTimeout => { - self.usart.cr1.modify(|_, w| w.rtoie().set_bit()) + self.usart().cr1.modify(|_, w| w.rtoie().set_bit()) }, } } @@ -434,25 +438,25 @@ macro_rules! hal { pub fn unlisten(&mut self, event: Event) { match event { Event::Rxne => { - self.usart.cr1.modify(|_, w| w.rxneie().clear_bit()) + self.usart().cr1.modify(|_, w| w.rxneie().clear_bit()) }, Event::Txe => { - self.usart.cr1.modify(|_, w| w.txeie().clear_bit()) + self.usart().cr1.modify(|_, w| w.txeie().clear_bit()) }, Event::Idle => { - self.usart.cr1.modify(|_, w| w.idleie().clear_bit()) + self.usart().cr1.modify(|_, w| w.idleie().clear_bit()) }, Event::CharacterMatch => { - self.usart.cr1.modify(|_, w| w.cmie().clear_bit()) + self.usart().cr1.modify(|_, w| w.cmie().clear_bit()) }, Event::ReceiverTimeout => { - self.usart.cr1.modify(|_, w| w.rtoie().clear_bit()) + self.usart().cr1.modify(|_, w| w.rtoie().clear_bit()) }, } } /// Splits the `Serial` abstraction into a transmitter and a receiver half - pub fn split(self) -> (Tx, Rx) { + pub fn split(self) -> (Tx, Rx) { ( self.tx, self.rx, @@ -461,7 +465,7 @@ macro_rules! hal { /// Frees the USART peripheral pub fn release(self) -> (pac::$USARTX, PINS) { - (self.usart, self.pins) + (self.tx.usart, self.rx.pins) } } @@ -473,7 +477,7 @@ macro_rules! hal { } } - impl serial::Read for Rx { + impl serial::Read for Rx { type Error = Error; fn read(&mut self) -> nb::Result { @@ -505,7 +509,7 @@ macro_rules! hal { } } - impl serial::Write for Tx { + impl serial::Write for Tx { // NOTE(Void) See section "29.7 USART interrupts"; the only possible errors during // transmission are: clear to send (which is disabled in this case) errors and // framing errors (which only occur in SmartCard mode); neither of these apply to @@ -540,23 +544,22 @@ macro_rules! hal { } } - impl embedded_hal::blocking::serial::write::Default - for Tx {} + impl embedded_hal::blocking::serial::write::Default for Tx {} - pub type $rxdma = RxDma, $dmarxch>; - pub type $txdma = TxDma, $dmatxch>; + pub type $rxdma = RxDma, $dmarxch>; + pub type $txdma = TxDma, $dmatxch>; - impl Receive for $rxdma { + impl Receive for $rxdma { type RxChannel = $dmarxch; type TransmittedWord = u8; } - impl Transmit for $txdma { + impl Transmit for $txdma { type TxChannel = $dmatxch; type ReceivedWord = u8; } - impl TransferPayload for $rxdma { + impl TransferPayload for $rxdma { fn start(&mut self) { self.channel.start(); } @@ -565,7 +568,7 @@ macro_rules! hal { } } - impl TransferPayload for $txdma { + impl TransferPayload for $txdma { fn start(&mut self) { self.channel.start(); } @@ -574,8 +577,8 @@ macro_rules! hal { } } - impl Rx { - pub fn with_dma(self, channel: $dmarxch) -> $rxdma { + impl Rx { + pub fn with_dma(self, channel: $dmarxch) -> $rxdma { RxDma { payload: self, channel, @@ -643,7 +646,7 @@ macro_rules! hal { } } - impl crate::dma::CharacterMatch for Rx { + impl crate::dma::CharacterMatch for Rx { /// Checks to see if the USART peripheral has detected an character match and /// clears the flag fn check_character_match(&mut self, clear: bool) -> bool { @@ -651,20 +654,20 @@ macro_rules! hal { } } - impl crate::dma::ReceiverTimeout for Rx { + impl crate::dma::ReceiverTimeout for Rx { fn check_receiver_timeout(&mut self, clear: bool) -> bool { self.is_receiver_timeout(clear) } } - impl crate::dma::OperationError<(), Error> for Rx{ + impl crate::dma::OperationError<(), Error> for Rx { fn check_operation_error(&mut self) -> Result<(), Error> { self.check_for_error() } } - impl Tx { - pub fn with_dma(self, channel: $dmatxch) -> $txdma { + impl Tx { + pub fn with_dma(self, channel: $dmatxch) -> $txdma { TxDma { payload: self, channel, @@ -672,8 +675,8 @@ macro_rules! hal { } } - impl $rxdma { - pub fn split(mut self) -> (Rx, $dmarxch) { + impl $rxdma { + pub fn split(mut self) -> (Rx, $dmarxch) { self.stop(); let RxDma {payload, channel} = self; ( @@ -683,8 +686,8 @@ macro_rules! hal { } } - impl $txdma { - pub fn split(mut self) -> (Tx, $dmatxch) { + impl $txdma { + pub fn split(mut self) -> (Tx, $dmatxch) { self.stop(); let TxDma {payload, channel} = self; ( @@ -694,7 +697,7 @@ macro_rules! hal { } } - impl crate::dma::CircReadDma for $rxdma + impl crate::dma::CircReadDma for $rxdma where &'static mut B: StaticWriteBuffer, B: 'static, @@ -746,7 +749,7 @@ macro_rules! hal { } } - impl $rxdma { + impl $rxdma { /// Create a frame reader that can either react on the Character match interrupt or /// Transfer Complete from the DMA. pub fn frame_reader( @@ -796,7 +799,7 @@ macro_rules! hal { } } - impl $txdma { + impl $txdma { /// Creates a new DMA frame sender pub fn frame_sender( mut self, @@ -836,6 +839,13 @@ macro_rules! hal { } } +impl From<(Tx, Rx)> for Serial { + /// Convert a transmitter/receiver back to a combined serial port. + fn from((tx, rx): (Tx, Rx)) -> Self { + Self { tx, rx } + } +} + hal! { USART1: (usart1, pclk2, tx: (TxDma1, dma1::C4, DmaInput::Usart1Tx), rx: (RxDma1, dma1::C5, DmaInput::Usart1Rx)), USART2: (usart2, pclk1, tx: (TxDma2, dma1::C7, DmaInput::Usart2Tx), rx: (RxDma2, dma1::C6, DmaInput::Usart2Rx)), @@ -905,9 +915,9 @@ where } } -impl fmt::Write for Tx +impl fmt::Write for Tx where - Tx: crate::hal::serial::Write, + Tx: crate::hal::serial::Write, { fn write_str(&mut self, s: &str) -> fmt::Result { let _ = s From 48d4f93fd01528cd8cdf8eebb6559ad1c26eaf7c Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Sun, 15 May 2022 06:13:57 +0200 Subject: [PATCH 3/4] Add check functions to `CircBuffer`. --- src/dma.rs | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/dma.rs b/src/dma.rs index 946bffc1..edf82dc4 100644 --- a/src/dma.rs +++ b/src/dma.rs @@ -333,6 +333,35 @@ where } } +impl CircBuffer> +where + PAYLOAD: CharacterMatch, +{ + /// Checks to see if the peripheral has detected a character match and + /// clears the flag + pub fn check_character_match(&mut self, clear: bool) -> bool { + self.payload.payload.check_character_match(clear) + } +} + +impl CircBuffer> +where + PAYLOAD: ReceiverTimeout, +{ + pub fn check_receiver_timeout(&mut self, clear: bool) -> bool { + self.payload.payload.check_receiver_timeout(clear) + } +} + +impl CircBuffer> { + pub fn check_operation_error(&mut self) -> Result + where + PAYLOAD: OperationError, + { + self.payload.payload.check_operation_error() + } +} + pub trait DmaExt { type Channels; From f00caf62c7055d13bd1879c0516eed3ee33b8230 Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Sun, 15 May 2022 21:50:16 +0200 Subject: [PATCH 4/4] Fix examples. --- examples/rtic_frame_serial_dma.rs | 16 ++++++++++++---- examples/serial_echo_rtic.rs | 8 ++++++-- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/examples/rtic_frame_serial_dma.rs b/examples/rtic_frame_serial_dma.rs index 04742658..51970ab0 100644 --- a/examples/rtic_frame_serial_dma.rs +++ b/examples/rtic_frame_serial_dma.rs @@ -24,8 +24,14 @@ use heapless::{ use panic_halt as _; use rtic::app; use stm32l4xx_hal as hal; -use stm32l4xx_hal::dma::{RxDma, TxDma}; -use stm32l4xx_hal::serial::{Rx, Tx}; +use stm32l4xx_hal::{ + dma::{RxDma, TxDma}, + gpio::{self, Alternate, PushPull}, + serial::{Rx, Tx}, +}; + +type TxPin = gpio::PA2>; +type RxPin = gpio::PA3>; // The pool gives out `Box`s that can hold 8 bytes pool!( @@ -36,8 +42,10 @@ pool!( #[app(device = stm32l4xx_hal::stm32, peripherals = true)] const APP: () = { struct Resources { - frame_reader: FrameReader, RxDma, dma::dma1::C6>, 8>, - frame_sender: FrameSender, TxDma, dma::dma1::C7>, 8>, + frame_reader: + FrameReader, RxDma, dma::dma1::C6>, 8>, + frame_sender: + FrameSender, TxDma, dma::dma1::C7>, 8>, } #[init] diff --git a/examples/serial_echo_rtic.rs b/examples/serial_echo_rtic.rs index e2a81027..e3f39169 100644 --- a/examples/serial_echo_rtic.rs +++ b/examples/serial_echo_rtic.rs @@ -7,16 +7,20 @@ use heapless::{consts::U8, spsc}; use nb::block; use rtt_target::{rprint, rprintln}; use stm32l4xx_hal::{ + gpio::{self, Alternate, PushPull}, pac::{self, USART2}, prelude::*, serial::{self, Config, Serial}, }; +type TxPin = gpio::PA2>; +type RxPin = gpio::PA3>; + #[rtic::app(device = stm32l4xx_hal::pac)] const APP: () = { struct Resources { - rx: serial::Rx, - tx: serial::Tx, + rx: serial::Rx, + tx: serial::Tx, rx_prod: spsc::Producer<'static, u8, U8>, rx_cons: spsc::Consumer<'static, u8, U8>,