diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index 7cab10d0..a835093c 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs @@ -1,14 +1,18 @@ #![macro_use] -#[cfg_attr(usart_v1, path = "v1.rs")] -#[cfg_attr(usart_v2, path = "v2.rs")] -mod _version; -use crate::{dma, peripherals}; -pub use _version::*; - -use crate::gpio::Pin; -use crate::rcc::RccPeripheral; +use core::future::Future; +use core::marker::PhantomData; use embassy::interrupt::Interrupt; +use embassy::util::Unborrow; +use embassy_hal_common::unborrow; +use futures::TryFutureExt; + +use crate::dma::NoDma; +use crate::gpio::sealed::AFType::{OutputOpenDrain, OutputPushPull}; +use crate::gpio::Pin; +use crate::pac::usart::{regs, vals}; +use crate::rcc::RccPeripheral; +use crate::{dma, peripherals}; #[derive(Clone, Copy, PartialEq, Eq, Debug)] pub enum DataBits { @@ -70,6 +74,414 @@ pub enum Error { Parity, } +pub struct Uart<'d, T: Instance, TxDma = NoDma, RxDma = NoDma> { + inner: T, + phantom: PhantomData<&'d mut T>, + tx_dma: TxDma, + rx_dma: RxDma, +} + +impl<'d, T: Instance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { + pub fn new( + inner: impl Unborrow, + rx: impl Unborrow>, + tx: impl Unborrow>, + tx_dma: impl Unborrow, + rx_dma: impl Unborrow, + config: Config, + ) -> Self { + unborrow!(inner, rx, tx, tx_dma, rx_dma); + + T::enable(); + let pclk_freq = T::frequency(); + + // TODO: better calculation, including error checking and OVER8 if possible. + let div = (pclk_freq.0 + (config.baudrate / 2)) / config.baudrate; + + let r = inner.regs(); + + unsafe { + rx.set_as_af(rx.af_num(), OutputOpenDrain); + tx.set_as_af(tx.af_num(), OutputPushPull); + + r.cr2().write(|_w| {}); + r.cr3().write(|_w| {}); + r.brr().write_value(regs::Brr(div)); + r.cr1().write(|w| { + w.set_ue(true); + w.set_te(true); + w.set_re(true); + w.set_m0(vals::M0::BIT8); + w.set_pce(config.parity != Parity::ParityNone); + w.set_ps(match config.parity { + Parity::ParityOdd => vals::Ps::ODD, + Parity::ParityEven => vals::Ps::EVEN, + _ => vals::Ps::EVEN, + }); + }); + } + + Self { + inner, + phantom: PhantomData, + tx_dma, + rx_dma, + } + } + + async fn write_dma(&mut self, buffer: &[u8]) -> Result<(), Error> + where + TxDma: crate::usart::TxDma, + { + let ch = &mut self.tx_dma; + let request = ch.request(); + unsafe { + self.inner.regs().cr3().modify(|reg| { + reg.set_dmat(true); + }); + } + let r = self.inner.regs(); + let dst = tdr(r); + crate::dma::write(ch, request, buffer, dst).await; + Ok(()) + } + + async fn read_dma(&mut self, buffer: &mut [u8]) -> Result<(), Error> + where + RxDma: crate::usart::RxDma, + { + let ch = &mut self.rx_dma; + let request = ch.request(); + unsafe { + self.inner.regs().cr3().modify(|reg| { + reg.set_dmar(true); + }); + } + let r = self.inner.regs(); + let src = rdr(r); + crate::dma::read(ch, request, src, buffer).await; + Ok(()) + } + + pub fn read_blocking(&mut self, buffer: &mut [u8]) -> Result<(), Error> { + unsafe { + let r = self.inner.regs(); + for b in buffer { + loop { + let sr = sr(r).read(); + if sr.pe() { + rdr(r).read_volatile(); + return Err(Error::Parity); + } else if sr.fe() { + rdr(r).read_volatile(); + return Err(Error::Framing); + } else if sr.ne() { + rdr(r).read_volatile(); + return Err(Error::Noise); + } else if sr.ore() { + rdr(r).read_volatile(); + return Err(Error::Overrun); + } else if sr.rxne() { + break; + } + } + *b = rdr(r).read_volatile(); + } + } + Ok(()) + } +} + +impl<'d, T: Instance, RxDma> embedded_hal::blocking::serial::Write + for Uart<'d, T, NoDma, RxDma> +{ + type Error = Error; + fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> { + unsafe { + let r = self.inner.regs(); + for &b in buffer { + while !sr(r).read().txe() {} + tdr(r).write_volatile(b); + } + } + Ok(()) + } + fn bflush(&mut self) -> Result<(), Self::Error> { + unsafe { + let r = self.inner.regs(); + while !sr(r).read().tc() {} + } + Ok(()) + } +} + +impl<'d, T: Instance, TxDma, RxDma> embassy_traits::uart::Write for Uart<'d, T, TxDma, RxDma> +where + TxDma: crate::usart::TxDma, +{ + #[rustfmt::skip] + type WriteFuture<'a> where Self: 'a = impl Future> + 'a; + + fn write<'a>(&'a mut self, buf: &'a [u8]) -> Self::WriteFuture<'a> { + self.write_dma(buf) + .map_err(|_| embassy_traits::uart::Error::Other) + } +} + +impl<'d, T: Instance, TxDma, RxDma> embassy_traits::uart::Read for Uart<'d, T, TxDma, RxDma> +where + RxDma: crate::usart::RxDma, +{ + #[rustfmt::skip] + type ReadFuture<'a> where Self: 'a = impl Future> + 'a; + + fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReadFuture<'a> { + self.read_dma(buf) + .map_err(|_| embassy_traits::uart::Error::Other) + } +} + +#[cfg(usart_v2)] +pub use buffered::*; +#[cfg(usart_v2)] +mod buffered { + use atomic_polyfill::{compiler_fence, Ordering}; + use core::pin::Pin; + use core::task::Context; + use core::task::Poll; + use embassy::waitqueue::WakerRegistration; + use embassy_hal_common::peripheral::{PeripheralMutex, PeripheralState, StateStorage}; + use embassy_hal_common::ring_buffer::RingBuffer; + + use super::*; + + pub struct State<'d, T: Instance>(StateStorage>); + impl<'d, T: Instance> State<'d, T> { + pub fn new() -> Self { + Self(StateStorage::new()) + } + } + + struct StateInner<'d, T: Instance> { + uart: Uart<'d, T, NoDma, NoDma>, + phantom: PhantomData<&'d mut T>, + + rx_waker: WakerRegistration, + rx: RingBuffer<'d>, + + tx_waker: WakerRegistration, + tx: RingBuffer<'d>, + } + + unsafe impl<'d, T: Instance> Send for StateInner<'d, T> {} + unsafe impl<'d, T: Instance> Sync for StateInner<'d, T> {} + + pub struct BufferedUart<'d, T: Instance> { + inner: PeripheralMutex<'d, StateInner<'d, T>>, + } + + impl<'d, T: Instance> Unpin for BufferedUart<'d, T> {} + + impl<'d, T: Instance> BufferedUart<'d, T> { + pub unsafe fn new( + state: &'d mut State<'d, T>, + uart: Uart<'d, T, NoDma, NoDma>, + irq: impl Unborrow + 'd, + tx_buffer: &'d mut [u8], + rx_buffer: &'d mut [u8], + ) -> BufferedUart<'d, T> { + unborrow!(irq); + + let r = uart.inner.regs(); + r.cr1().modify(|w| { + w.set_rxneie(true); + w.set_idleie(true); + }); + + Self { + inner: PeripheralMutex::new_unchecked(irq, &mut state.0, move || StateInner { + uart, + phantom: PhantomData, + tx: RingBuffer::new(tx_buffer), + tx_waker: WakerRegistration::new(), + + rx: RingBuffer::new(rx_buffer), + rx_waker: WakerRegistration::new(), + }), + } + } + } + + impl<'d, T: Instance> StateInner<'d, T> + where + Self: 'd, + { + fn on_rx(&mut self) { + let r = self.uart.inner.regs(); + unsafe { + let sr = r.isr().read(); + if sr.pe() { + r.icr().write(|w| { + w.set_pe(true); + }); + trace!("Parity error"); + } else if sr.fe() { + r.icr().write(|w| { + w.set_fe(true); + }); + trace!("Framing error"); + } else if sr.ne() { + r.icr().write(|w| { + w.set_ne(true); + }); + trace!("Noise error"); + } else if sr.ore() { + r.icr().write(|w| { + w.set_ore(true); + }); + trace!("Overrun error"); + } else if sr.rxne() { + let buf = self.rx.push_buf(); + if buf.is_empty() { + self.rx_waker.wake(); + } else { + buf[0] = r.rdr().read().0 as u8; + self.rx.push(1); + } + } else if sr.idle() { + r.icr().write(|w| { + w.set_idle(true); + }); + self.rx_waker.wake(); + }; + } + } + + fn on_tx(&mut self) { + let r = self.uart.inner.regs(); + unsafe { + if r.isr().read().txe() { + let buf = self.tx.pop_buf(); + if !buf.is_empty() { + r.cr1().modify(|w| { + w.set_txeie(true); + }); + r.tdr().write_value(regs::Dr(buf[0].into())); + self.tx.pop(1); + self.tx_waker.wake(); + } else { + // Disable interrupt until we have something to transmit again + r.cr1().modify(|w| { + w.set_txeie(false); + }); + } + } + } + } + } + + impl<'d, T: Instance> PeripheralState for StateInner<'d, T> + where + Self: 'd, + { + type Interrupt = T::Interrupt; + fn on_interrupt(&mut self) { + self.on_rx(); + self.on_tx(); + } + } + + impl<'d, T: Instance> embassy::io::AsyncBufRead for BufferedUart<'d, T> { + fn poll_fill_buf( + mut self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll> { + self.inner.with(|state| { + compiler_fence(Ordering::SeqCst); + + // We have data ready in buffer? Return it. + let buf = state.rx.pop_buf(); + if !buf.is_empty() { + let buf: &[u8] = buf; + // Safety: buffer lives as long as uart + let buf: &[u8] = unsafe { core::mem::transmute(buf) }; + return Poll::Ready(Ok(buf)); + } + + state.rx_waker.register(cx.waker()); + Poll::>::Pending + }) + } + fn consume(mut self: Pin<&mut Self>, amt: usize) { + let signal = self.inner.with(|state| { + let full = state.rx.is_full(); + state.rx.pop(amt); + full + }); + if signal { + self.inner.pend(); + } + } + } + + impl<'d, T: Instance> embassy::io::AsyncWrite for BufferedUart<'d, T> { + fn poll_write( + mut self: Pin<&mut Self>, + cx: &mut Context<'_>, + buf: &[u8], + ) -> Poll> { + let (poll, empty) = self.inner.with(|state| { + let empty = state.tx.is_empty(); + let tx_buf = state.tx.push_buf(); + if tx_buf.is_empty() { + state.tx_waker.register(cx.waker()); + return (Poll::Pending, empty); + } + + let n = core::cmp::min(tx_buf.len(), buf.len()); + tx_buf[..n].copy_from_slice(&buf[..n]); + state.tx.push(n); + + (Poll::Ready(Ok(n)), empty) + }); + if empty { + self.inner.pend(); + } + poll + } + } +} + +#[cfg(usart_v1)] +fn tdr(r: crate::pac::usart::Usart) -> *mut u8 { + r.dr().ptr() as _ +} + +#[cfg(usart_v1)] +fn rdr(r: crate::pac::usart::Usart) -> *mut u8 { + r.dr().ptr() as _ +} + +#[cfg(usart_v1)] +fn sr(r: crate::pac::usart::Usart) -> crate::pac::common::Reg { + r.sr() +} + +#[cfg(usart_v2)] +fn tdr(r: crate::pac::usart::Usart) -> *mut u8 { + r.tdr().ptr() as _ +} + +#[cfg(usart_v2)] +fn rdr(r: crate::pac::usart::Usart) -> *mut u8 { + r.rdr().ptr() as _ +} + +#[cfg(usart_v2)] +fn sr(r: crate::pac::usart::Usart) -> crate::pac::common::Reg { + r.isr() +} + pub(crate) mod sealed { use super::*; diff --git a/embassy-stm32/src/usart/v1.rs b/embassy-stm32/src/usart/v1.rs deleted file mode 100644 index 10f87f2d..00000000 --- a/embassy-stm32/src/usart/v1.rs +++ /dev/null @@ -1,176 +0,0 @@ -use crate::gpio::sealed::AFType::{OutputOpenDrain, OutputPushPull}; -use core::future::Future; -use core::marker::PhantomData; -use embassy::util::Unborrow; -use embassy_hal_common::unborrow; -use futures::TryFutureExt; - -use super::*; -use crate::dma::NoDma; -use crate::pac::usart::{regs, vals}; - -pub struct Uart<'d, T: Instance, TxDma = NoDma, RxDma = NoDma> { - inner: T, - phantom: PhantomData<&'d mut T>, - tx_dma: TxDma, - #[allow(dead_code)] - rx_dma: RxDma, -} - -impl<'d, T: Instance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { - pub fn new( - inner: impl Unborrow, - rx: impl Unborrow>, - tx: impl Unborrow>, - tx_dma: impl Unborrow, - rx_dma: impl Unborrow, - config: Config, - ) -> Self { - unborrow!(inner, rx, tx, tx_dma, rx_dma); - - T::enable(); - let pclk_freq = T::frequency(); - - // TODO: better calculation, including error checking and OVER8 if possible. - let div = (pclk_freq.0 + (config.baudrate / 2)) / config.baudrate; - - let r = inner.regs(); - - unsafe { - rx.set_as_af(rx.af_num(), OutputOpenDrain); - tx.set_as_af(tx.af_num(), OutputPushPull); - - r.brr().write_value(regs::Brr(div)); - r.cr1().write(|w| { - w.set_ue(true); - w.set_te(true); - w.set_re(true); - w.set_m(vals::M::M8); - w.set_pce(config.parity != Parity::ParityNone); - w.set_ps(match config.parity { - Parity::ParityOdd => vals::Ps::ODD, - Parity::ParityEven => vals::Ps::EVEN, - _ => vals::Ps::EVEN, - }); - }); - r.cr2().write(|_w| {}); - r.cr3().write(|_w| {}); - } - - Self { - inner, - phantom: PhantomData, - tx_dma, - rx_dma, - } - } - - async fn write_dma(&mut self, buffer: &[u8]) -> Result<(), Error> - where - TxDma: crate::usart::TxDma, - { - let ch = &mut self.tx_dma; - let request = ch.request(); - unsafe { - self.inner.regs().cr3().modify(|reg| { - reg.set_dmat(true); - }); - } - let r = self.inner.regs(); - let dst = r.dr().ptr() as *mut u8; - crate::dma::write(ch, request, buffer, dst).await; - Ok(()) - } - - async fn read_dma(&mut self, buffer: &mut [u8]) -> Result<(), Error> - where - RxDma: crate::usart::RxDma, - { - let ch = &mut self.rx_dma; - let request = ch.request(); - unsafe { - self.inner.regs().cr3().modify(|reg| { - reg.set_dmar(true); - }); - } - let r = self.inner.regs(); - let src = r.dr().ptr() as *mut u8; - crate::dma::read(ch, request, src, buffer).await; - Ok(()) - } - - pub fn read_blocking(&mut self, buffer: &mut [u8]) -> Result<(), Error> { - unsafe { - let r = self.inner.regs(); - for b in buffer { - loop { - let sr = r.sr().read(); - if sr.pe() { - r.dr().read(); - return Err(Error::Parity); - } else if sr.fe() { - r.dr().read(); - return Err(Error::Framing); - } else if sr.ne() { - r.dr().read(); - return Err(Error::Noise); - } else if sr.ore() { - r.dr().read(); - return Err(Error::Overrun); - } else if sr.rxne() { - break; - } - } - *b = r.dr().read().0 as u8; - } - } - Ok(()) - } -} - -impl<'d, T: Instance, RxDma> embedded_hal::blocking::serial::Write - for Uart<'d, T, NoDma, RxDma> -{ - type Error = Error; - fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> { - unsafe { - let r = self.inner.regs(); - for &b in buffer { - while !r.sr().read().txe() {} - r.dr().write_value(regs::Dr(b as u32)) - } - } - Ok(()) - } - fn bflush(&mut self) -> Result<(), Self::Error> { - unsafe { - let r = self.inner.regs(); - while !r.sr().read().tc() {} - } - Ok(()) - } -} - -// rustfmt::skip because intellij removes the 'where' claus on the associated type. -#[rustfmt::skip] -impl<'d, T: Instance, TxDma, RxDma> embassy_traits::uart::Write for Uart<'d, T, TxDma, RxDma> - where TxDma: crate::usart::TxDma -{ - type WriteFuture<'a> where Self: 'a = impl Future> + 'a; - - fn write<'a>(&'a mut self, buf: &'a [u8]) -> Self::WriteFuture<'a> { - self.write_dma(buf).map_err(|_| embassy_traits::uart::Error::Other) - } -} - -// rustfmt::skip because intellij removes the 'where' claus on the associated type. -#[rustfmt::skip] -impl<'d, T: Instance, TxDma, RxDma> embassy_traits::uart::Read for Uart<'d, T, TxDma, RxDma> - where RxDma: crate::usart::RxDma -{ - type ReadFuture<'a> where Self: 'a = impl Future> + 'a; - - fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReadFuture<'a> { - self.read_dma(buf).map_err(|_| embassy_traits::uart::Error::Other) - } -} diff --git a/embassy-stm32/src/usart/v2.rs b/embassy-stm32/src/usart/v2.rs deleted file mode 100644 index 697adf45..00000000 --- a/embassy-stm32/src/usart/v2.rs +++ /dev/null @@ -1,388 +0,0 @@ -use atomic_polyfill::{compiler_fence, Ordering}; -use core::future::Future; -use core::marker::PhantomData; -use core::pin::Pin; -use core::task::Context; -use core::task::Poll; -use embassy::util::Unborrow; -use embassy::waitqueue::WakerRegistration; -use embassy_hal_common::peripheral::{PeripheralMutex, PeripheralState, StateStorage}; -use embassy_hal_common::ring_buffer::RingBuffer; -use embassy_hal_common::unborrow; -use futures::TryFutureExt; - -use super::*; -use crate::dma::NoDma; -use crate::gpio::sealed::AFType::{OutputOpenDrain, OutputPushPull}; -use crate::pac::usart::{regs, vals}; - -pub struct Uart<'d, T: Instance, TxDma = NoDma, RxDma = NoDma> { - inner: T, - phantom: PhantomData<&'d mut T>, - tx_dma: TxDma, - rx_dma: RxDma, -} - -impl<'d, T: Instance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { - pub fn new( - inner: impl Unborrow, - rx: impl Unborrow>, - tx: impl Unborrow>, - tx_dma: impl Unborrow, - rx_dma: impl Unborrow, - config: Config, - ) -> Self { - unborrow!(inner, rx, tx, tx_dma, rx_dma); - - T::enable(); - let pclk_freq = T::frequency(); - - // TODO: better calculation, including error checking and OVER8 if possible. - let div = (pclk_freq.0 + (config.baudrate / 2)) / config.baudrate; - - let r = inner.regs(); - - unsafe { - rx.set_as_af(rx.af_num(), OutputOpenDrain); - tx.set_as_af(tx.af_num(), OutputPushPull); - - r.cr2().write(|_w| {}); - r.cr3().write(|_w| {}); - - r.brr().write(|w| w.set_brr(div as u16)); - r.cr1().write(|w| { - w.set_ue(true); - w.set_te(true); - w.set_re(true); - w.set_m0(vals::M0::BIT8); - w.set_m1(vals::M1::M0); - w.set_pce(config.parity != Parity::ParityNone); - w.set_ps(match config.parity { - Parity::ParityOdd => vals::Ps::ODD, - Parity::ParityEven => vals::Ps::EVEN, - _ => vals::Ps::EVEN, - }); - }); - r.cr2().write(|_w| {}); - r.cr3().write(|_w| {}); - } - - Self { - inner, - phantom: PhantomData, - tx_dma, - rx_dma, - } - } - - async fn write_dma(&mut self, buffer: &[u8]) -> Result<(), Error> - where - TxDma: crate::usart::TxDma, - { - let ch = &mut self.tx_dma; - let request = ch.request(); - unsafe { - self.inner.regs().cr3().modify(|reg| { - reg.set_dmat(true); - }); - } - let r = self.inner.regs(); - let dst = r.tdr().ptr() as *mut u8; - crate::dma::write(ch, request, buffer, dst).await; - Ok(()) - } - - async fn read_dma(&mut self, buffer: &mut [u8]) -> Result<(), Error> - where - RxDma: crate::usart::RxDma, - { - let ch = &mut self.rx_dma; - let request = ch.request(); - unsafe { - self.inner.regs().cr3().modify(|reg| { - reg.set_dmar(true); - }); - } - let r = self.inner.regs(); - let src = r.rdr().ptr() as *mut u8; - - crate::dma::read(ch, request, src, buffer).await; - Ok(()) - } - - pub fn read_blocking(&mut self, buffer: &mut [u8]) -> Result<(), Error> { - unsafe { - let r = self.inner.regs(); - for b in buffer { - loop { - let sr = r.isr().read(); - if sr.pe() { - r.rdr().read(); - return Err(Error::Parity); - } else if sr.fe() { - r.rdr().read(); - return Err(Error::Framing); - } else if sr.nf() { - r.rdr().read(); - return Err(Error::Noise); - } else if sr.ore() { - r.rdr().read(); - return Err(Error::Overrun); - } else if sr.rxne() { - break; - } - } - *b = r.rdr().read().0 as u8; - } - } - Ok(()) - } -} - -impl<'d, T: Instance, RxDma> embedded_hal::blocking::serial::Write - for Uart<'d, T, NoDma, RxDma> -{ - type Error = Error; - fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> { - unsafe { - let r = self.inner.regs(); - for &b in buffer { - while !r.isr().read().txe() {} - r.tdr().write_value(regs::Dr(b as u32)) - } - } - Ok(()) - } - fn bflush(&mut self) -> Result<(), Self::Error> { - unsafe { - let r = self.inner.regs(); - while !r.isr().read().tc() {} - } - Ok(()) - } -} - -// rustfmt::skip because intellij removes the 'where' claus on the associated type. -impl<'d, T: Instance, TxDma, RxDma> embassy_traits::uart::Write for Uart<'d, T, TxDma, RxDma> -where - TxDma: crate::usart::TxDma, -{ - // rustfmt::skip because rustfmt removes the 'where' claus on the associated type. - #[rustfmt::skip] - type WriteFuture<'a> where Self: 'a = impl Future> +'a; - - fn write<'a>(&'a mut self, buf: &'a [u8]) -> Self::WriteFuture<'a> { - self.write_dma(buf) - .map_err(|_| embassy_traits::uart::Error::Other) - } -} - -impl<'d, T: Instance, TxDma, RxDma> embassy_traits::uart::Read for Uart<'d, T, TxDma, RxDma> -where - RxDma: crate::usart::RxDma, -{ - // rustfmt::skip because rustfmt removes the 'where' claus on the associated type. - #[rustfmt::skip] - type ReadFuture<'a> where Self: 'a = impl Future> + 'a; - - fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReadFuture<'a> { - self.read_dma(buf) - .map_err(|_| embassy_traits::uart::Error::Other) - } -} - -pub struct State<'d, T: Instance>(StateStorage>); -impl<'d, T: Instance> State<'d, T> { - pub fn new() -> Self { - Self(StateStorage::new()) - } -} - -pub struct StateInner<'d, T: Instance> { - uart: Uart<'d, T, NoDma, NoDma>, - phantom: PhantomData<&'d mut T>, - - rx_waker: WakerRegistration, - rx: RingBuffer<'d>, - - tx_waker: WakerRegistration, - tx: RingBuffer<'d>, -} - -unsafe impl<'d, T: Instance> Send for StateInner<'d, T> {} -unsafe impl<'d, T: Instance> Sync for StateInner<'d, T> {} - -pub struct BufferedUart<'d, T: Instance> { - inner: PeripheralMutex<'d, StateInner<'d, T>>, -} - -impl<'d, T: Instance> Unpin for BufferedUart<'d, T> {} - -impl<'d, T: Instance> BufferedUart<'d, T> { - pub unsafe fn new( - state: &'d mut State<'d, T>, - uart: Uart<'d, T, NoDma, NoDma>, - irq: impl Unborrow + 'd, - tx_buffer: &'d mut [u8], - rx_buffer: &'d mut [u8], - ) -> BufferedUart<'d, T> { - unborrow!(irq); - - let r = uart.inner.regs(); - r.cr1().modify(|w| { - w.set_rxneie(true); - w.set_idleie(true); - }); - - Self { - inner: PeripheralMutex::new_unchecked(irq, &mut state.0, move || StateInner { - uart, - phantom: PhantomData, - tx: RingBuffer::new(tx_buffer), - tx_waker: WakerRegistration::new(), - - rx: RingBuffer::new(rx_buffer), - rx_waker: WakerRegistration::new(), - }), - } - } -} - -impl<'d, T: Instance> StateInner<'d, T> -where - Self: 'd, -{ - fn on_rx(&mut self) { - let r = self.uart.inner.regs(); - unsafe { - let sr = r.isr().read(); - if sr.pe() { - r.icr().write(|w| { - w.set_pe(true); - }); - trace!("Parity error"); - } else if sr.fe() { - r.icr().write(|w| { - w.set_fe(true); - }); - trace!("Framing error"); - } else if sr.nf() { - r.icr().write(|w| { - w.set_nf(true); - }); - trace!("Noise error"); - } else if sr.ore() { - r.icr().write(|w| { - w.set_ore(true); - }); - trace!("Overrun error"); - } else if sr.rxne() { - let buf = self.rx.push_buf(); - if buf.is_empty() { - self.rx_waker.wake(); - } else { - buf[0] = r.rdr().read().0 as u8; - self.rx.push(1); - } - } else if sr.idle() { - r.icr().write(|w| { - w.set_idle(true); - }); - self.rx_waker.wake(); - }; - } - } - - fn on_tx(&mut self) { - let r = self.uart.inner.regs(); - unsafe { - if r.isr().read().txe() { - let buf = self.tx.pop_buf(); - if !buf.is_empty() { - r.cr1().modify(|w| { - w.set_txeie(true); - }); - r.tdr().write_value(regs::Dr(buf[0].into())); - self.tx.pop(1); - self.tx_waker.wake(); - } else { - // Disable interrupt until we have something to transmit again - r.cr1().modify(|w| { - w.set_txeie(false); - }); - } - } - } - } -} - -impl<'d, T: Instance> PeripheralState for StateInner<'d, T> -where - Self: 'd, -{ - type Interrupt = T::Interrupt; - fn on_interrupt(&mut self) { - self.on_rx(); - self.on_tx(); - } -} - -impl<'d, T: Instance> embassy::io::AsyncBufRead for BufferedUart<'d, T> { - fn poll_fill_buf( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll> { - self.inner.with(|state| { - compiler_fence(Ordering::SeqCst); - - // We have data ready in buffer? Return it. - let buf = state.rx.pop_buf(); - if !buf.is_empty() { - let buf: &[u8] = buf; - // Safety: buffer lives as long as uart - let buf: &[u8] = unsafe { core::mem::transmute(buf) }; - return Poll::Ready(Ok(buf)); - } - - state.rx_waker.register(cx.waker()); - Poll::>::Pending - }) - } - fn consume(mut self: Pin<&mut Self>, amt: usize) { - let signal = self.inner.with(|state| { - let full = state.rx.is_full(); - state.rx.pop(amt); - full - }); - if signal { - self.inner.pend(); - } - } -} - -impl<'d, T: Instance> embassy::io::AsyncWrite for BufferedUart<'d, T> { - fn poll_write( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - buf: &[u8], - ) -> Poll> { - let (poll, empty) = self.inner.with(|state| { - let empty = state.tx.is_empty(); - let tx_buf = state.tx.push_buf(); - if tx_buf.is_empty() { - state.tx_waker.register(cx.waker()); - return (Poll::Pending, empty); - } - - let n = core::cmp::min(tx_buf.len(), buf.len()); - tx_buf[..n].copy_from_slice(&buf[..n]); - state.tx.push(n); - - (Poll::Ready(Ok(n)), empty) - }); - if empty { - self.inner.pend(); - } - poll - } -} diff --git a/stm32-data b/stm32-data index 3e883bdf..5506d274 160000 --- a/stm32-data +++ b/stm32-data @@ -1 +1 @@ -Subproject commit 3e883bdff7fbb1f96be353d2c062be57ec8921a3 +Subproject commit 5506d27471c7e3297450127c3279f3dab96c94f8