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()); tx.set_as_af(tx.af_num()); 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; unsafe { self.inner.regs().cr3().modify(|reg| { reg.set_dmat(true); }); } let r = self.inner.regs(); let dst = r.dr().ptr() as *mut u8; ch.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; unsafe { self.inner.regs().cr3().modify(|reg| { reg.set_dmar(true); }); } let r = self.inner.regs(); let src = r.dr().ptr() as *mut u8; ch.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) } }