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>, 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; diff --git a/src/serial.rs b/src/serial.rs index 2e36c7b4..836ca582 100644 --- a/src/serial.rs +++ b/src/serial.rs @@ -206,18 +206,20 @@ impl From for Config { /// Serial abstraction pub struct Serial { - usart: USART, - pins: PINS, + 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 { @@ -372,26 +374,34 @@ macro_rules! hal { .cr1 .modify(|_, w| w.ue().set_bit().re().set_bit().te().set_bit()); - Serial { usart, pins } + Serial { + 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()) }, } } @@ -400,48 +410,62 @@ 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 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) { ( - Tx { - _usart: PhantomData, - }, - Rx { - _usart: PhantomData, - }, + self.tx, + self.rx, ) } /// Frees the USART peripheral pub fn release(self) -> (pac::$USARTX, PINS) { - (self.usart, self.pins) + (self.tx.usart, self.rx.pins) } } @@ -449,14 +473,11 @@ macro_rules! hal { type Error = Error; fn read(&mut self) -> nb::Result { - let mut rx: Rx = Rx { - _usart: PhantomData, - }; - rx.read() + self.rx.read() } } - impl serial::Read for Rx { + impl serial::Read for Rx { type Error = Error; fn read(&mut self) -> nb::Result { @@ -480,21 +501,15 @@ 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) } } - 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 @@ -529,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(); } @@ -554,7 +568,7 @@ macro_rules! hal { } } - impl TransferPayload for $txdma { + impl TransferPayload for $txdma { fn start(&mut self) { self.channel.start(); } @@ -563,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, @@ -579,28 +593,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 @@ -653,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 { @@ -661,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, @@ -682,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; ( @@ -693,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; ( @@ -704,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, @@ -756,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( @@ -806,7 +799,7 @@ macro_rules! hal { } } - impl $txdma { + impl $txdma { /// Creates a new DMA frame sender pub fn frame_sender( mut self, @@ -846,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)), @@ -915,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