From a56ddfdc04a02d9de2dc474f5cc9dbae8cff1ab1 Mon Sep 17 00:00:00 2001 From: Thales Fragoso Date: Sun, 4 Jul 2021 15:40:33 -0300 Subject: [PATCH] STM: Add usart v2 --- embassy-stm32/src/bdma/v1.rs | 38 +++++++---- embassy-stm32/src/usart/v2.rs | 118 ++++++++++++++++++++++++++++++++++ 2 files changed, 143 insertions(+), 13 deletions(-) diff --git a/embassy-stm32/src/bdma/v1.rs b/embassy-stm32/src/bdma/v1.rs index 584d531f7..13caf329b 100644 --- a/embassy-stm32/src/bdma/v1.rs +++ b/embassy-stm32/src/bdma/v1.rs @@ -35,13 +35,15 @@ impl State { static STATE: State = State::new(); #[allow(unused)] -pub(crate) async unsafe fn transfer_p2m(ch: &mut impl Channel, src: *const u8, dst: &mut [u8]) { +pub(crate) async unsafe fn transfer_p2m( + regs: pac::bdma::Ch, + state_number: usize, + src: *const u8, + dst: &mut [u8], +) { // ndtr is max 16 bits. assert!(dst.len() <= 0xFFFF); - let regs: pac::bdma::Ch = ch.regs(); - let state_number = ch.state_num(); - // Reset status // Generate a DMB here to flush the store buffer (M7) before enabling the DMA STATE.ch_status[state_number].store(CH_STATUS_NONE, Ordering::Release); @@ -82,13 +84,15 @@ pub(crate) async unsafe fn transfer_p2m(ch: &mut impl Channel, src: *const u8, d } #[allow(unused)] -pub(crate) async unsafe fn transfer_m2p(ch: &mut impl Channel, src: &[u8], dst: *mut u8) { +pub(crate) async unsafe fn transfer_m2p( + regs: pac::bdma::Ch, + state_number: usize, + src: &[u8], + dst: *mut u8, +) { // ndtr is max 16 bits. assert!(src.len() <= 0xFFFF); - let regs: pac::bdma::Ch = ch.regs(); - let state_number = ch.state_num(); - // Reset status // Generate a DMB here to flush the store buffer (M7) before enabling the DMA STATE.ch_status[state_number].store(CH_STATUS_NONE, Ordering::Release); @@ -168,7 +172,7 @@ pub(crate) mod sealed { } pub trait Channel { - fn dma_regs() -> &'static pac::bdma::Dma; + fn dma_regs() -> pac::bdma::Dma; fn state_num(&self) -> usize; @@ -199,8 +203,8 @@ macro_rules! impl_dma_channel { impl Channel for crate::peripherals::$channel_peri {} impl sealed::Channel for crate::peripherals::$channel_peri { #[inline] - fn dma_regs() -> &'static pac::bdma::Dma { - &crate::pac::$dma_peri + fn dma_regs() -> pac::bdma::Dma { + crate::pac::$dma_peri } fn state_num(&self) -> usize { @@ -222,7 +226,11 @@ macro_rules! impl_dma_channel { where T: 'a, { - unsafe { transfer_m2p(self, buf, dst) } + use sealed::Channel as _Channel; + + let state_num = self.state_num(); + let regs = self.regs(); + unsafe { transfer_m2p(regs, state_num, buf, dst) } } } @@ -240,7 +248,11 @@ macro_rules! impl_dma_channel { where T: 'a, { - unsafe { transfer_p2m(self, src, buf) } + use sealed::Channel as _Channel; + + let state_num = self.state_num(); + let regs = self.regs(); + unsafe { transfer_p2m(regs, state_num, src, buf) } } } }; diff --git a/embassy-stm32/src/usart/v2.rs b/embassy-stm32/src/usart/v2.rs index 8b1378917..271eff850 100644 --- a/embassy-stm32/src/usart/v2.rs +++ b/embassy-stm32/src/usart/v2.rs @@ -1 +1,119 @@ +use core::marker::PhantomData; +use embassy::util::Unborrow; +use embassy_extras::unborrow; + +use crate::pac::usart::{regs, vals}; + +use super::*; + +pub struct Uart<'d, T: Instance> { + inner: T, + phantom: PhantomData<&'d mut T>, +} + +impl<'d, T: Instance> Uart<'d, T> { + pub fn new( + inner: impl Unborrow, + rx: impl Unborrow>, + tx: impl Unborrow>, + config: Config, + ) -> Self { + unborrow!(inner, rx, tx); + + // Uncomment once we find all of the H7's UART clocks. + T::enable(); + let pclk_freq = T::frequency(); + + // TODO: better calculation, including error checking and OVER8 if possible. + let div = pclk_freq.0 / 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_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, + } + } + + #[cfg(dma)] + pub async fn write_dma(&mut self, ch: &mut impl TxDma, buffer: &[u8]) -> Result<(), Error> { + unsafe { + self.inner.regs().cr3().modify(|reg| { + reg.set_dmat(true); + }); + } + let r = self.inner.regs(); + let dst = r.tdr().ptr() as *mut u8; + ch.transfer(buffer, dst).await; + Ok(()) + } + + pub fn read(&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.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> embedded_hal::blocking::serial::Write for Uart<'d, T> { + 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(|w| w.set_dr(b as u16)); + } + } + Ok(()) + } + fn bflush(&mut self) -> Result<(), Self::Error> { + unsafe { + let r = self.inner.regs(); + while !r.isr().read().tc() {} + } + Ok(()) + } +}