Merge #1031
1031: stm32: Add support for read_until_idle on UART - rebase r=Dirbaio a=Dirbaio `@guillaume-michel` I rebased #1011 for you and then noticed you don't have the "allowed maintainers to push" option so I had to open a new PR. bors r+ Co-authored-by: Guillaume MICHEL <guillaume@squaremind.io>
This commit is contained in:
		
						commit
						9b86de770b
					
				| @ -46,16 +46,44 @@ impl<'d, T: BasicInstance> Unpin for BufferedUart<'d, T> {} | |||||||
| impl<'d, T: BasicInstance> BufferedUart<'d, T> { | impl<'d, T: BasicInstance> BufferedUart<'d, T> { | ||||||
|     pub fn new( |     pub fn new( | ||||||
|         state: &'d mut State<'d, T>, |         state: &'d mut State<'d, T>, | ||||||
|         _uart: Uart<'d, T, NoDma, NoDma>, |         _peri: impl Peripheral<P = T> + 'd, | ||||||
|  |         rx: impl Peripheral<P = impl RxPin<T>> + 'd, | ||||||
|  |         tx: impl Peripheral<P = impl TxPin<T>> + 'd, | ||||||
|         irq: impl Peripheral<P = T::Interrupt> + 'd, |         irq: impl Peripheral<P = T::Interrupt> + 'd, | ||||||
|         tx_buffer: &'d mut [u8], |         tx_buffer: &'d mut [u8], | ||||||
|         rx_buffer: &'d mut [u8], |         rx_buffer: &'d mut [u8], | ||||||
|  |         config: Config, | ||||||
|     ) -> BufferedUart<'d, T> { |     ) -> BufferedUart<'d, T> { | ||||||
|         into_ref!(irq); |         into_ref!(_peri, rx, tx, irq); | ||||||
|  | 
 | ||||||
|  |         T::enable(); | ||||||
|  |         T::reset(); | ||||||
| 
 | 
 | ||||||
|         let r = T::regs(); |         let r = T::regs(); | ||||||
|  | 
 | ||||||
|  |         configure(r, &config, T::frequency(), T::MULTIPLIER); | ||||||
|  | 
 | ||||||
|         unsafe { |         unsafe { | ||||||
|             r.cr1().modify(|w| { |             rx.set_as_af(rx.af_num(), AFType::Input); | ||||||
|  |             tx.set_as_af(tx.af_num(), AFType::OutputPushPull); | ||||||
|  | 
 | ||||||
|  |             r.cr2().write(|_w| {}); | ||||||
|  |             r.cr3().write(|_w| {}); | ||||||
|  |             r.cr1().write(|w| { | ||||||
|  |                 w.set_ue(true); | ||||||
|  |                 w.set_te(true); | ||||||
|  |                 w.set_re(true); | ||||||
|  |                 w.set_m0(if config.parity != Parity::ParityNone { | ||||||
|  |                     vals::M0::BIT9 | ||||||
|  |                 } else { | ||||||
|  |                     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, | ||||||
|  |                 }); | ||||||
|                 w.set_rxneie(true); |                 w.set_rxneie(true); | ||||||
|                 w.set_idleie(true); |                 w.set_idleie(true); | ||||||
|             }); |             }); | ||||||
|  | |||||||
| @ -1,7 +1,11 @@ | |||||||
| #![macro_use] | #![macro_use] | ||||||
| 
 | 
 | ||||||
|  | use core::future::poll_fn; | ||||||
| use core::marker::PhantomData; | use core::marker::PhantomData; | ||||||
|  | use core::task::Poll; | ||||||
| 
 | 
 | ||||||
|  | use atomic_polyfill::{compiler_fence, Ordering}; | ||||||
|  | use embassy_cortex_m::interrupt::InterruptExt; | ||||||
| use embassy_hal_common::{into_ref, PeripheralRef}; | use embassy_hal_common::{into_ref, PeripheralRef}; | ||||||
| 
 | 
 | ||||||
| use crate::dma::NoDma; | use crate::dma::NoDma; | ||||||
| @ -10,6 +14,7 @@ use crate::gpio::sealed::AFType; | |||||||
| use crate::pac::lpuart::{regs, vals, Lpuart as Regs}; | use crate::pac::lpuart::{regs, vals, Lpuart as Regs}; | ||||||
| #[cfg(not(any(lpuart_v1, lpuart_v2)))] | #[cfg(not(any(lpuart_v1, lpuart_v2)))] | ||||||
| use crate::pac::usart::{regs, vals, Usart as Regs}; | use crate::pac::usart::{regs, vals, Usart as Regs}; | ||||||
|  | use crate::time::Hertz; | ||||||
| use crate::{peripherals, Peripheral}; | use crate::{peripherals, Peripheral}; | ||||||
| 
 | 
 | ||||||
| #[derive(Clone, Copy, PartialEq, Eq, Debug)] | #[derive(Clone, Copy, PartialEq, Eq, Debug)] | ||||||
| @ -44,6 +49,10 @@ pub struct Config { | |||||||
|     pub data_bits: DataBits, |     pub data_bits: DataBits, | ||||||
|     pub stop_bits: StopBits, |     pub stop_bits: StopBits, | ||||||
|     pub parity: Parity, |     pub parity: Parity, | ||||||
|  |     /// if true, on read-like method, if there is a latent error pending,
 | ||||||
|  |     /// read will abort, the error reported and cleared
 | ||||||
|  |     /// if false, the error is ignored and cleared
 | ||||||
|  |     pub detect_previous_overrun: bool, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl Default for Config { | impl Default for Config { | ||||||
| @ -53,6 +62,8 @@ impl Default for Config { | |||||||
|             data_bits: DataBits::DataBits8, |             data_bits: DataBits::DataBits8, | ||||||
|             stop_bits: StopBits::STOP1, |             stop_bits: StopBits::STOP1, | ||||||
|             parity: Parity::ParityNone, |             parity: Parity::ParityNone, | ||||||
|  |             // historical behavior
 | ||||||
|  |             detect_previous_overrun: false, | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @ -70,10 +81,11 @@ pub enum Error { | |||||||
|     Overrun, |     Overrun, | ||||||
|     /// Parity check error
 |     /// Parity check error
 | ||||||
|     Parity, |     Parity, | ||||||
|  |     /// Buffer too large for DMA
 | ||||||
|  |     BufferTooLong, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub struct Uart<'d, T: BasicInstance, TxDma = NoDma, RxDma = NoDma> { | pub struct Uart<'d, T: BasicInstance, TxDma = NoDma, RxDma = NoDma> { | ||||||
|     phantom: PhantomData<&'d mut T>, |  | ||||||
|     tx: UartTx<'d, T, TxDma>, |     tx: UartTx<'d, T, TxDma>, | ||||||
|     rx: UartRx<'d, T, RxDma>, |     rx: UartRx<'d, T, RxDma>, | ||||||
| } | } | ||||||
| @ -84,8 +96,9 @@ pub struct UartTx<'d, T: BasicInstance, TxDma = NoDma> { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub struct UartRx<'d, T: BasicInstance, RxDma = NoDma> { | pub struct UartRx<'d, T: BasicInstance, RxDma = NoDma> { | ||||||
|     phantom: PhantomData<&'d mut T>, |     _peri: PeripheralRef<'d, T>, | ||||||
|     rx_dma: PeripheralRef<'d, RxDma>, |     rx_dma: PeripheralRef<'d, RxDma>, | ||||||
|  |     detect_previous_overrun: bool, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> { | impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> { | ||||||
| @ -135,10 +148,112 @@ impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> { | impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> { | ||||||
|     fn new(rx_dma: PeripheralRef<'d, RxDma>) -> Self { |     /// usefull if you only want Uart Rx. It saves 1 pin and consumes a little less power
 | ||||||
|  |     pub fn new( | ||||||
|  |         peri: impl Peripheral<P = T> + 'd, | ||||||
|  |         irq: impl Peripheral<P = T::Interrupt> + 'd, | ||||||
|  |         rx: impl Peripheral<P = impl RxPin<T>> + 'd, | ||||||
|  |         rx_dma: impl Peripheral<P = RxDma> + 'd, | ||||||
|  |         config: Config, | ||||||
|  |     ) -> Self { | ||||||
|  |         into_ref!(peri, irq, rx, rx_dma); | ||||||
|  | 
 | ||||||
|  |         T::enable(); | ||||||
|  |         T::reset(); | ||||||
|  | 
 | ||||||
|  |         let r = T::regs(); | ||||||
|  | 
 | ||||||
|  |         configure(r, &config, T::frequency(), T::MULTIPLIER); | ||||||
|  | 
 | ||||||
|  |         unsafe { | ||||||
|  |             rx.set_as_af(rx.af_num(), AFType::Input); | ||||||
|  | 
 | ||||||
|  |             r.cr2().write(|_w| {}); | ||||||
|  |             r.cr3().write(|w| { | ||||||
|  |                 // enable Error Interrupt: (Frame error, Noise error, Overrun error)
 | ||||||
|  |                 w.set_eie(true); | ||||||
|  |             }); | ||||||
|  |             r.cr1().write(|w| { | ||||||
|  |                 // enable uart
 | ||||||
|  |                 w.set_ue(true); | ||||||
|  |                 // enable receiver
 | ||||||
|  |                 w.set_re(true); | ||||||
|  |                 // configure word size
 | ||||||
|  |                 w.set_m0(if config.parity != Parity::ParityNone { | ||||||
|  |                     vals::M0::BIT9 | ||||||
|  |                 } else { | ||||||
|  |                     vals::M0::BIT8 | ||||||
|  |                 }); | ||||||
|  |                 // configure parity
 | ||||||
|  |                 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, | ||||||
|  |                 }); | ||||||
|  |             }); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         irq.set_handler(Self::on_interrupt); | ||||||
|  |         irq.unpend(); | ||||||
|  |         irq.enable(); | ||||||
|  | 
 | ||||||
|  |         // create state once!
 | ||||||
|  |         let _s = T::state(); | ||||||
|  | 
 | ||||||
|         Self { |         Self { | ||||||
|  |             _peri: peri, | ||||||
|             rx_dma, |             rx_dma, | ||||||
|             phantom: PhantomData, |             detect_previous_overrun: config.detect_previous_overrun, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn on_interrupt(_: *mut ()) { | ||||||
|  |         let r = T::regs(); | ||||||
|  |         let s = T::state(); | ||||||
|  | 
 | ||||||
|  |         let (sr, cr1, cr3) = unsafe { (sr(r).read(), r.cr1().read(), r.cr3().read()) }; | ||||||
|  | 
 | ||||||
|  |         let has_errors = (sr.pe() && cr1.peie()) || ((sr.fe() || sr.ne() || sr.ore()) && cr3.eie()); | ||||||
|  | 
 | ||||||
|  |         if has_errors { | ||||||
|  |             // clear all interrupts and DMA Rx Request
 | ||||||
|  |             unsafe { | ||||||
|  |                 r.cr1().modify(|w| { | ||||||
|  |                     // disable RXNE interrupt
 | ||||||
|  |                     w.set_rxneie(false); | ||||||
|  |                     // disable parity interrupt
 | ||||||
|  |                     w.set_peie(false); | ||||||
|  |                     // disable idle line interrupt
 | ||||||
|  |                     w.set_idleie(false); | ||||||
|  |                 }); | ||||||
|  |                 r.cr3().modify(|w| { | ||||||
|  |                     // disable Error Interrupt: (Frame error, Noise error, Overrun error)
 | ||||||
|  |                     w.set_eie(false); | ||||||
|  |                     // disable DMA Rx Request
 | ||||||
|  |                     w.set_dmar(false); | ||||||
|  |                 }); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             compiler_fence(Ordering::SeqCst); | ||||||
|  | 
 | ||||||
|  |             s.rx_waker.wake(); | ||||||
|  |         } else if cr1.idleie() && sr.idle() { | ||||||
|  |             // IDLE detected: no more data will come
 | ||||||
|  |             unsafe { | ||||||
|  |                 r.cr1().modify(|w| { | ||||||
|  |                     // disable idle line detection
 | ||||||
|  |                     w.set_idleie(false); | ||||||
|  |                 }); | ||||||
|  | 
 | ||||||
|  |                 r.cr3().modify(|w| { | ||||||
|  |                     // disable DMA Rx Request
 | ||||||
|  |                     w.set_dmar(false); | ||||||
|  |                 }); | ||||||
|  |             } | ||||||
|  |             compiler_fence(Ordering::SeqCst); | ||||||
|  | 
 | ||||||
|  |             s.rx_waker.wake(); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -146,17 +261,8 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> { | |||||||
|     where |     where | ||||||
|         RxDma: crate::usart::RxDma<T>, |         RxDma: crate::usart::RxDma<T>, | ||||||
|     { |     { | ||||||
|         let ch = &mut self.rx_dma; |         self.inner_read(buffer, false).await?; | ||||||
|         let request = ch.request(); | 
 | ||||||
|         unsafe { |  | ||||||
|             T::regs().cr3().modify(|reg| { |  | ||||||
|                 reg.set_dmar(true); |  | ||||||
|             }); |  | ||||||
|         } |  | ||||||
|         // If we don't assign future to a variable, the data register pointer
 |  | ||||||
|         // is held across an await and makes the future non-Send.
 |  | ||||||
|         let transfer = crate::dma::read(ch, request, rdr(T::regs()), buffer); |  | ||||||
|         transfer.await; |  | ||||||
|         Ok(()) |         Ok(()) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -211,13 +317,202 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> { | |||||||
|         } |         } | ||||||
|         Ok(()) |         Ok(()) | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     pub async fn read_until_idle(&mut self, buffer: &mut [u8]) -> Result<usize, Error> | ||||||
|  |     where | ||||||
|  |         RxDma: crate::usart::RxDma<T>, | ||||||
|  |     { | ||||||
|  |         self.inner_read(buffer, true).await | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     async fn inner_read(&mut self, buffer: &mut [u8], enable_idle_line_detection: bool) -> Result<usize, Error> | ||||||
|  |     where | ||||||
|  |         RxDma: crate::usart::RxDma<T>, | ||||||
|  |     { | ||||||
|  |         if buffer.is_empty() { | ||||||
|  |             return Ok(0); | ||||||
|  |         } else if buffer.len() > 0xFFFF { | ||||||
|  |             return Err(Error::BufferTooLong); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         let r = T::regs(); | ||||||
|  | 
 | ||||||
|  |         let buffer_len = buffer.len(); | ||||||
|  | 
 | ||||||
|  |         let ch = &mut self.rx_dma; | ||||||
|  |         let request = ch.request(); | ||||||
|  | 
 | ||||||
|  |         // SAFETY: The only way we might have a problem is using split rx and tx
 | ||||||
|  |         // here we only modify or read Rx related flags, interrupts and DMA channel
 | ||||||
|  |         unsafe { | ||||||
|  |             // Start USART DMA
 | ||||||
|  |             // will not do anything yet because DMAR is not yet set
 | ||||||
|  |             ch.start_read(request, rdr(r), buffer, Default::default()); | ||||||
|  | 
 | ||||||
|  |             // clear ORE flag just before enabling DMA Rx Request: can be mandatory for the second transfer
 | ||||||
|  |             if !self.detect_previous_overrun { | ||||||
|  |                 let sr = sr(r).read(); | ||||||
|  |                 // This read also clears the error and idle interrupt flags on v1.
 | ||||||
|  |                 rdr(r).read_volatile(); | ||||||
|  |                 clear_interrupt_flags(r, sr); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             r.cr1().modify(|w| { | ||||||
|  |                 // disable RXNE interrupt
 | ||||||
|  |                 w.set_rxneie(false); | ||||||
|  |                 // enable parity interrupt if not ParityNone
 | ||||||
|  |                 w.set_peie(w.pce()); | ||||||
|  |             }); | ||||||
|  | 
 | ||||||
|  |             r.cr3().modify(|w| { | ||||||
|  |                 // enable Error Interrupt: (Frame error, Noise error, Overrun error)
 | ||||||
|  |                 w.set_eie(true); | ||||||
|  |                 // enable DMA Rx Request
 | ||||||
|  |                 w.set_dmar(true); | ||||||
|  |             }); | ||||||
|  | 
 | ||||||
|  |             compiler_fence(Ordering::SeqCst); | ||||||
|  | 
 | ||||||
|  |             // In case of errors already pending when reception started, interrupts may have already been raised
 | ||||||
|  |             // and lead to reception abortion (Overrun error for instance). In such a case, all interrupts
 | ||||||
|  |             // have been disabled in interrupt handler and DMA Rx Request has been disabled.
 | ||||||
|  | 
 | ||||||
|  |             let cr3 = r.cr3().read(); | ||||||
|  | 
 | ||||||
|  |             if !cr3.dmar() { | ||||||
|  |                 // something went wrong
 | ||||||
|  |                 // because the only way to get this flag cleared is to have an interrupt
 | ||||||
|  | 
 | ||||||
|  |                 // abort DMA transfer
 | ||||||
|  |                 ch.request_stop(); | ||||||
|  |                 while ch.is_running() {} | ||||||
|  | 
 | ||||||
|  |                 let sr = sr(r).read(); | ||||||
|  |                 // This read also clears the error and idle interrupt flags on v1.
 | ||||||
|  |                 rdr(r).read_volatile(); | ||||||
|  |                 clear_interrupt_flags(r, sr); | ||||||
|  | 
 | ||||||
|  |                 if sr.pe() { | ||||||
|  |                     return Err(Error::Parity); | ||||||
|  |                 } | ||||||
|  |                 if sr.fe() { | ||||||
|  |                     return Err(Error::Framing); | ||||||
|  |                 } | ||||||
|  |                 if sr.ne() { | ||||||
|  |                     return Err(Error::Noise); | ||||||
|  |                 } | ||||||
|  |                 if sr.ore() { | ||||||
|  |                     return Err(Error::Overrun); | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 unreachable!(); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             // clear idle flag
 | ||||||
|  |             if enable_idle_line_detection { | ||||||
|  |                 let sr = sr(r).read(); | ||||||
|  |                 // This read also clears the error and idle interrupt flags on v1.
 | ||||||
|  |                 rdr(r).read_volatile(); | ||||||
|  |                 clear_interrupt_flags(r, sr); | ||||||
|  | 
 | ||||||
|  |                 // enable idle interrupt
 | ||||||
|  |                 r.cr1().modify(|w| { | ||||||
|  |                     w.set_idleie(true); | ||||||
|  |                 }); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         compiler_fence(Ordering::SeqCst); | ||||||
|  | 
 | ||||||
|  |         let res = poll_fn(move |cx| { | ||||||
|  |             let s = T::state(); | ||||||
|  | 
 | ||||||
|  |             ch.set_waker(cx.waker()); | ||||||
|  |             s.rx_waker.register(cx.waker()); | ||||||
|  | 
 | ||||||
|  |             // SAFETY: read only and we only use Rx related flags
 | ||||||
|  |             let sr = unsafe { sr(r).read() }; | ||||||
|  | 
 | ||||||
|  |             // SAFETY: only clears Rx related flags
 | ||||||
|  |             unsafe { | ||||||
|  |                 // This read also clears the error and idle interrupt flags on v1.
 | ||||||
|  |                 rdr(r).read_volatile(); | ||||||
|  |                 clear_interrupt_flags(r, sr); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             compiler_fence(Ordering::SeqCst); | ||||||
|  | 
 | ||||||
|  |             let has_errors = sr.pe() || sr.fe() || sr.ne() || sr.ore(); | ||||||
|  | 
 | ||||||
|  |             if has_errors { | ||||||
|  |                 // all Rx interrupts and Rx DMA Request have already been cleared in interrupt handler
 | ||||||
|  | 
 | ||||||
|  |                 // stop dma transfer
 | ||||||
|  |                 ch.request_stop(); | ||||||
|  |                 while ch.is_running() {} | ||||||
|  | 
 | ||||||
|  |                 if sr.pe() { | ||||||
|  |                     return Poll::Ready(Err(Error::Parity)); | ||||||
|  |                 } | ||||||
|  |                 if sr.fe() { | ||||||
|  |                     return Poll::Ready(Err(Error::Framing)); | ||||||
|  |                 } | ||||||
|  |                 if sr.ne() { | ||||||
|  |                     return Poll::Ready(Err(Error::Noise)); | ||||||
|  |                 } | ||||||
|  |                 if sr.ore() { | ||||||
|  |                     return Poll::Ready(Err(Error::Overrun)); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             if sr.idle() { | ||||||
|  |                 // Idle line
 | ||||||
|  | 
 | ||||||
|  |                 // stop dma transfer
 | ||||||
|  |                 ch.request_stop(); | ||||||
|  |                 while ch.is_running() {} | ||||||
|  | 
 | ||||||
|  |                 let n = buffer_len - (ch.remaining_transfers() as usize); | ||||||
|  | 
 | ||||||
|  |                 return Poll::Ready(Ok(n)); | ||||||
|  |             } else if !ch.is_running() { | ||||||
|  |                 // DMA complete
 | ||||||
|  |                 return Poll::Ready(Ok(buffer_len)); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             Poll::Pending | ||||||
|  |         }) | ||||||
|  |         .await; | ||||||
|  | 
 | ||||||
|  |         // clear all interrupts and DMA Rx Request
 | ||||||
|  |         // SAFETY: only clears Rx related flags
 | ||||||
|  |         unsafe { | ||||||
|  |             r.cr1().modify(|w| { | ||||||
|  |                 // disable RXNE interrupt
 | ||||||
|  |                 w.set_rxneie(false); | ||||||
|  |                 // disable parity interrupt
 | ||||||
|  |                 w.set_peie(false); | ||||||
|  |                 // disable idle line interrupt
 | ||||||
|  |                 w.set_idleie(false); | ||||||
|  |             }); | ||||||
|  |             r.cr3().modify(|w| { | ||||||
|  |                 // disable Error Interrupt: (Frame error, Noise error, Overrun error)
 | ||||||
|  |                 w.set_eie(false); | ||||||
|  |                 // disable DMA Rx Request
 | ||||||
|  |                 w.set_dmar(false); | ||||||
|  |             }); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         res | ||||||
|  |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { | impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { | ||||||
|     pub fn new( |     pub fn new( | ||||||
|         _inner: impl Peripheral<P = T> + 'd, |         peri: impl Peripheral<P = T> + 'd, | ||||||
|         rx: impl Peripheral<P = impl RxPin<T>> + 'd, |         rx: impl Peripheral<P = impl RxPin<T>> + 'd, | ||||||
|         tx: impl Peripheral<P = impl TxPin<T>> + 'd, |         tx: impl Peripheral<P = impl TxPin<T>> + 'd, | ||||||
|  |         irq: impl Peripheral<P = T::Interrupt> + 'd, | ||||||
|         tx_dma: impl Peripheral<P = TxDma> + 'd, |         tx_dma: impl Peripheral<P = TxDma> + 'd, | ||||||
|         rx_dma: impl Peripheral<P = RxDma> + 'd, |         rx_dma: impl Peripheral<P = RxDma> + 'd, | ||||||
|         config: Config, |         config: Config, | ||||||
| @ -225,13 +520,14 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { | |||||||
|         T::enable(); |         T::enable(); | ||||||
|         T::reset(); |         T::reset(); | ||||||
| 
 | 
 | ||||||
|         Self::new_inner(_inner, rx, tx, tx_dma, rx_dma, config) |         Self::new_inner(peri, rx, tx, irq, tx_dma, rx_dma, config) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn new_with_rtscts( |     pub fn new_with_rtscts( | ||||||
|         _inner: impl Peripheral<P = T> + 'd, |         peri: impl Peripheral<P = T> + 'd, | ||||||
|         rx: impl Peripheral<P = impl RxPin<T>> + 'd, |         rx: impl Peripheral<P = impl RxPin<T>> + 'd, | ||||||
|         tx: impl Peripheral<P = impl TxPin<T>> + 'd, |         tx: impl Peripheral<P = impl TxPin<T>> + 'd, | ||||||
|  |         irq: impl Peripheral<P = T::Interrupt> + 'd, | ||||||
|         rts: impl Peripheral<P = impl RtsPin<T>> + 'd, |         rts: impl Peripheral<P = impl RtsPin<T>> + 'd, | ||||||
|         cts: impl Peripheral<P = impl CtsPin<T>> + 'd, |         cts: impl Peripheral<P = impl CtsPin<T>> + 'd, | ||||||
|         tx_dma: impl Peripheral<P = TxDma> + 'd, |         tx_dma: impl Peripheral<P = TxDma> + 'd, | ||||||
| @ -251,32 +547,29 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { | |||||||
|                 w.set_ctse(true); |                 w.set_ctse(true); | ||||||
|             }); |             }); | ||||||
|         } |         } | ||||||
|         Self::new_inner(_inner, rx, tx, tx_dma, rx_dma, config) |         Self::new_inner(peri, rx, tx, irq, tx_dma, rx_dma, config) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn new_inner( |     fn new_inner( | ||||||
|         _inner: impl Peripheral<P = T> + 'd, |         peri: impl Peripheral<P = T> + 'd, | ||||||
|         rx: impl Peripheral<P = impl RxPin<T>> + 'd, |         rx: impl Peripheral<P = impl RxPin<T>> + 'd, | ||||||
|         tx: impl Peripheral<P = impl TxPin<T>> + 'd, |         tx: impl Peripheral<P = impl TxPin<T>> + 'd, | ||||||
|  |         irq: impl Peripheral<P = T::Interrupt> + 'd, | ||||||
|         tx_dma: impl Peripheral<P = TxDma> + 'd, |         tx_dma: impl Peripheral<P = TxDma> + 'd, | ||||||
|         rx_dma: impl Peripheral<P = RxDma> + 'd, |         rx_dma: impl Peripheral<P = RxDma> + 'd, | ||||||
|         config: Config, |         config: Config, | ||||||
|     ) -> Self { |     ) -> Self { | ||||||
|         into_ref!(_inner, rx, tx, tx_dma, rx_dma); |         into_ref!(peri, rx, tx, irq, tx_dma, rx_dma); | ||||||
| 
 |  | ||||||
|         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 * T::MULTIPLIER; |  | ||||||
| 
 | 
 | ||||||
|         let r = T::regs(); |         let r = T::regs(); | ||||||
| 
 | 
 | ||||||
|  |         configure(r, &config, T::frequency(), T::MULTIPLIER); | ||||||
|  | 
 | ||||||
|         unsafe { |         unsafe { | ||||||
|             rx.set_as_af(rx.af_num(), AFType::Input); |             rx.set_as_af(rx.af_num(), AFType::Input); | ||||||
|             tx.set_as_af(tx.af_num(), AFType::OutputPushPull); |             tx.set_as_af(tx.af_num(), AFType::OutputPushPull); | ||||||
| 
 | 
 | ||||||
|             r.cr2().write(|_w| {}); |             r.cr2().write(|_w| {}); | ||||||
|             r.brr().write_value(regs::Brr(div)); |  | ||||||
|             r.cr1().write(|w| { |             r.cr1().write(|w| { | ||||||
|                 w.set_ue(true); |                 w.set_ue(true); | ||||||
|                 w.set_te(true); |                 w.set_te(true); | ||||||
| @ -295,10 +588,20 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { | |||||||
|             }); |             }); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         irq.set_handler(UartRx::<T, RxDma>::on_interrupt); | ||||||
|  |         irq.unpend(); | ||||||
|  |         irq.enable(); | ||||||
|  | 
 | ||||||
|  |         // create state once!
 | ||||||
|  |         let _s = T::state(); | ||||||
|  | 
 | ||||||
|         Self { |         Self { | ||||||
|             tx: UartTx::new(tx_dma), |             tx: UartTx::new(tx_dma), | ||||||
|             rx: UartRx::new(rx_dma), |             rx: UartRx { | ||||||
|             phantom: PhantomData {}, |                 _peri: peri, | ||||||
|  |                 rx_dma, | ||||||
|  |                 detect_previous_overrun: config.detect_previous_overrun, | ||||||
|  |             }, | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -332,6 +635,13 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { | |||||||
|         self.rx.blocking_read(buffer) |         self.rx.blocking_read(buffer) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     pub async fn read_until_idle(&mut self, buffer: &mut [u8]) -> Result<usize, Error> | ||||||
|  |     where | ||||||
|  |         RxDma: crate::usart::RxDma<T>, | ||||||
|  |     { | ||||||
|  |         self.rx.read_until_idle(buffer).await | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     /// Split the Uart into a transmitter and receiver, which is
 |     /// Split the Uart into a transmitter and receiver, which is
 | ||||||
|     /// particuarly useful when having two tasks correlating to
 |     /// particuarly useful when having two tasks correlating to
 | ||||||
|     /// transmitting and receiving.
 |     /// transmitting and receiving.
 | ||||||
| @ -340,6 +650,15 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | fn configure(r: Regs, config: &Config, pclk_freq: Hertz, multiplier: u32) { | ||||||
|  |     // TODO: better calculation, including error checking and OVER8 if possible.
 | ||||||
|  |     let div = (pclk_freq.0 + (config.baudrate / 2)) / config.baudrate * multiplier; | ||||||
|  | 
 | ||||||
|  |     unsafe { | ||||||
|  |         r.brr().write_value(regs::Brr(div)); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| mod eh02 { | mod eh02 { | ||||||
|     use super::*; |     use super::*; | ||||||
| 
 | 
 | ||||||
| @ -389,6 +708,7 @@ mod eh1 { | |||||||
|                 Self::Noise => embedded_hal_1::serial::ErrorKind::Noise, |                 Self::Noise => embedded_hal_1::serial::ErrorKind::Noise, | ||||||
|                 Self::Overrun => embedded_hal_1::serial::ErrorKind::Overrun, |                 Self::Overrun => embedded_hal_1::serial::ErrorKind::Overrun, | ||||||
|                 Self::Parity => embedded_hal_1::serial::ErrorKind::Parity, |                 Self::Parity => embedded_hal_1::serial::ErrorKind::Parity, | ||||||
|  |                 Self::BufferTooLong => embedded_hal_1::serial::ErrorKind::Other, | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| @ -573,13 +893,30 @@ unsafe fn clear_interrupt_flags(r: Regs, sr: regs::Isr) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub(crate) mod sealed { | pub(crate) mod sealed { | ||||||
|  |     use embassy_sync::waitqueue::AtomicWaker; | ||||||
|  | 
 | ||||||
|     use super::*; |     use super::*; | ||||||
| 
 | 
 | ||||||
|  |     pub struct State { | ||||||
|  |         pub rx_waker: AtomicWaker, | ||||||
|  |         pub tx_waker: AtomicWaker, | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     impl State { | ||||||
|  |         pub const fn new() -> Self { | ||||||
|  |             Self { | ||||||
|  |                 rx_waker: AtomicWaker::new(), | ||||||
|  |                 tx_waker: AtomicWaker::new(), | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     pub trait BasicInstance: crate::rcc::RccPeripheral { |     pub trait BasicInstance: crate::rcc::RccPeripheral { | ||||||
|         const MULTIPLIER: u32; |         const MULTIPLIER: u32; | ||||||
|         type Interrupt: crate::interrupt::Interrupt; |         type Interrupt: crate::interrupt::Interrupt; | ||||||
| 
 | 
 | ||||||
|         fn regs() -> Regs; |         fn regs() -> Regs; | ||||||
|  |         fn state() -> &'static State; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub trait FullInstance: BasicInstance { |     pub trait FullInstance: BasicInstance { | ||||||
| @ -587,7 +924,7 @@ pub(crate) mod sealed { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub trait BasicInstance: sealed::BasicInstance {} | pub trait BasicInstance: Peripheral<P = Self> + sealed::BasicInstance + 'static + Send {} | ||||||
| 
 | 
 | ||||||
| pub trait FullInstance: sealed::FullInstance {} | pub trait FullInstance: sealed::FullInstance {} | ||||||
| 
 | 
 | ||||||
| @ -609,6 +946,11 @@ macro_rules! impl_lpuart { | |||||||
|             fn regs() -> Regs { |             fn regs() -> Regs { | ||||||
|                 Regs(crate::pac::$inst.0) |                 Regs(crate::pac::$inst.0) | ||||||
|             } |             } | ||||||
|  | 
 | ||||||
|  |             fn state() -> &'static crate::usart::sealed::State { | ||||||
|  |                 static STATE: crate::usart::sealed::State = crate::usart::sealed::State::new(); | ||||||
|  |                 &STATE | ||||||
|  |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         impl BasicInstance for peripherals::$inst {} |         impl BasicInstance for peripherals::$inst {} | ||||||
|  | |||||||
| @ -7,6 +7,7 @@ use core::fmt::Write; | |||||||
| use defmt::*; | use defmt::*; | ||||||
| use embassy_executor::Spawner; | use embassy_executor::Spawner; | ||||||
| use embassy_stm32::dma::NoDma; | use embassy_stm32::dma::NoDma; | ||||||
|  | use embassy_stm32::interrupt; | ||||||
| use embassy_stm32::usart::{Config, Uart}; | use embassy_stm32::usart::{Config, Uart}; | ||||||
| use heapless::String; | use heapless::String; | ||||||
| use {defmt_rtt as _, panic_probe as _}; | use {defmt_rtt as _, panic_probe as _}; | ||||||
| @ -17,7 +18,8 @@ async fn main(_spawner: Spawner) { | |||||||
|     info!("Hello World!"); |     info!("Hello World!"); | ||||||
| 
 | 
 | ||||||
|     let config = Config::default(); |     let config = Config::default(); | ||||||
|     let mut usart = Uart::new(p.USART1, p.PE1, p.PE0, p.DMA1_CH4, NoDma, config); |     let irq = interrupt::take!(USART1); | ||||||
|  |     let mut usart = Uart::new(p.USART1, p.PE1, p.PE0, irq, p.DMA1_CH4, NoDma, config); | ||||||
| 
 | 
 | ||||||
|     for n in 0u32.. { |     for n in 0u32.. { | ||||||
|         let mut s: String<128> = String::new(); |         let mut s: String<128> = String::new(); | ||||||
|  | |||||||
| @ -5,6 +5,7 @@ | |||||||
| use cortex_m_rt::entry; | use cortex_m_rt::entry; | ||||||
| use defmt::*; | use defmt::*; | ||||||
| use embassy_stm32::dma::NoDma; | use embassy_stm32::dma::NoDma; | ||||||
|  | use embassy_stm32::interrupt; | ||||||
| use embassy_stm32::usart::{Config, Uart}; | use embassy_stm32::usart::{Config, Uart}; | ||||||
| use {defmt_rtt as _, panic_probe as _}; | use {defmt_rtt as _, panic_probe as _}; | ||||||
| 
 | 
 | ||||||
| @ -15,7 +16,8 @@ fn main() -> ! { | |||||||
|     let p = embassy_stm32::init(Default::default()); |     let p = embassy_stm32::init(Default::default()); | ||||||
| 
 | 
 | ||||||
|     let config = Config::default(); |     let config = Config::default(); | ||||||
|     let mut usart = Uart::new(p.USART3, p.PD9, p.PD8, NoDma, NoDma, config); |     let irq = interrupt::take!(USART3); | ||||||
|  |     let mut usart = Uart::new(p.USART3, p.PD9, p.PD8, irq, NoDma, NoDma, config); | ||||||
| 
 | 
 | ||||||
|     unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n")); |     unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n")); | ||||||
|     info!("wrote Hello, starting echo"); |     info!("wrote Hello, starting echo"); | ||||||
|  | |||||||
| @ -4,9 +4,8 @@ | |||||||
| 
 | 
 | ||||||
| use defmt::*; | use defmt::*; | ||||||
| use embassy_executor::Spawner; | use embassy_executor::Spawner; | ||||||
| use embassy_stm32::dma::NoDma; |  | ||||||
| use embassy_stm32::interrupt; | use embassy_stm32::interrupt; | ||||||
| use embassy_stm32::usart::{BufferedUart, Config, State, Uart}; | use embassy_stm32::usart::{BufferedUart, Config, State}; | ||||||
| use embedded_io::asynch::BufRead; | use embedded_io::asynch::BufRead; | ||||||
| use {defmt_rtt as _, panic_probe as _}; | use {defmt_rtt as _, panic_probe as _}; | ||||||
| 
 | 
 | ||||||
| @ -16,13 +15,21 @@ async fn main(_spawner: Spawner) { | |||||||
|     info!("Hello World!"); |     info!("Hello World!"); | ||||||
| 
 | 
 | ||||||
|     let config = Config::default(); |     let config = Config::default(); | ||||||
|     let usart = Uart::new(p.USART3, p.PD9, p.PD8, NoDma, NoDma, config); |  | ||||||
| 
 | 
 | ||||||
|     let mut state = State::new(); |     let mut state = State::new(); | ||||||
|     let irq = interrupt::take!(USART3); |     let irq = interrupt::take!(USART3); | ||||||
|     let mut tx_buf = [0u8; 32]; |     let mut tx_buf = [0u8; 32]; | ||||||
|     let mut rx_buf = [0u8; 32]; |     let mut rx_buf = [0u8; 32]; | ||||||
|     let mut buf_usart = BufferedUart::new(&mut state, usart, irq, &mut tx_buf, &mut rx_buf); |     let mut buf_usart = BufferedUart::new( | ||||||
|  |         &mut state, | ||||||
|  |         p.USART3, | ||||||
|  |         p.PD9, | ||||||
|  |         p.PD8, | ||||||
|  |         irq, | ||||||
|  |         &mut tx_buf, | ||||||
|  |         &mut rx_buf, | ||||||
|  |         config, | ||||||
|  |     ); | ||||||
| 
 | 
 | ||||||
|     loop { |     loop { | ||||||
|         let buf = buf_usart.fill_buf().await.unwrap(); |         let buf = buf_usart.fill_buf().await.unwrap(); | ||||||
|  | |||||||
| @ -7,6 +7,7 @@ use core::fmt::Write; | |||||||
| use defmt::*; | use defmt::*; | ||||||
| use embassy_executor::Spawner; | use embassy_executor::Spawner; | ||||||
| use embassy_stm32::dma::NoDma; | use embassy_stm32::dma::NoDma; | ||||||
|  | use embassy_stm32::interrupt; | ||||||
| use embassy_stm32::usart::{Config, Uart}; | use embassy_stm32::usart::{Config, Uart}; | ||||||
| use heapless::String; | use heapless::String; | ||||||
| use {defmt_rtt as _, panic_probe as _}; | use {defmt_rtt as _, panic_probe as _}; | ||||||
| @ -17,7 +18,8 @@ async fn main(_spawner: Spawner) { | |||||||
|     info!("Hello World!"); |     info!("Hello World!"); | ||||||
| 
 | 
 | ||||||
|     let config = Config::default(); |     let config = Config::default(); | ||||||
|     let mut usart = Uart::new(p.USART3, p.PD9, p.PD8, p.DMA1_CH3, NoDma, config); |     let irq = interrupt::take!(USART3); | ||||||
|  |     let mut usart = Uart::new(p.USART3, p.PD9, p.PD8, irq, p.DMA1_CH3, NoDma, config); | ||||||
| 
 | 
 | ||||||
|     for n in 0u32.. { |     for n in 0u32.. { | ||||||
|         let mut s: String<128> = String::new(); |         let mut s: String<128> = String::new(); | ||||||
|  | |||||||
| @ -7,6 +7,7 @@ use core::fmt::Write; | |||||||
| use defmt::*; | use defmt::*; | ||||||
| use embassy_executor::Spawner; | use embassy_executor::Spawner; | ||||||
| use embassy_stm32::dma::NoDma; | use embassy_stm32::dma::NoDma; | ||||||
|  | use embassy_stm32::interrupt; | ||||||
| use embassy_stm32::usart::{Config, Uart}; | use embassy_stm32::usart::{Config, Uart}; | ||||||
| use heapless::String; | use heapless::String; | ||||||
| use {defmt_rtt as _, panic_probe as _}; | use {defmt_rtt as _, panic_probe as _}; | ||||||
| @ -15,7 +16,8 @@ use {defmt_rtt as _, panic_probe as _}; | |||||||
| async fn main(_spawner: Spawner) { | async fn main(_spawner: Spawner) { | ||||||
|     let p = embassy_stm32::init(Default::default()); |     let p = embassy_stm32::init(Default::default()); | ||||||
|     let config = Config::default(); |     let config = Config::default(); | ||||||
|     let mut usart = Uart::new(p.UART7, p.PA8, p.PA15, p.DMA1_CH1, NoDma, config); |     let irq = interrupt::take!(UART7); | ||||||
|  |     let mut usart = Uart::new(p.UART7, p.PA8, p.PA15, irq, p.DMA1_CH1, NoDma, config); | ||||||
| 
 | 
 | ||||||
|     for n in 0u32.. { |     for n in 0u32.. { | ||||||
|         let mut s: String<128> = String::new(); |         let mut s: String<128> = String::new(); | ||||||
|  | |||||||
| @ -6,6 +6,7 @@ use cortex_m_rt::entry; | |||||||
| use defmt::*; | use defmt::*; | ||||||
| use embassy_executor::Executor; | use embassy_executor::Executor; | ||||||
| use embassy_stm32::dma::NoDma; | use embassy_stm32::dma::NoDma; | ||||||
|  | use embassy_stm32::interrupt; | ||||||
| use embassy_stm32::usart::{Config, Uart}; | use embassy_stm32::usart::{Config, Uart}; | ||||||
| use static_cell::StaticCell; | use static_cell::StaticCell; | ||||||
| use {defmt_rtt as _, panic_probe as _}; | use {defmt_rtt as _, panic_probe as _}; | ||||||
| @ -15,7 +16,8 @@ async fn main_task() { | |||||||
|     let p = embassy_stm32::init(Default::default()); |     let p = embassy_stm32::init(Default::default()); | ||||||
| 
 | 
 | ||||||
|     let config = Config::default(); |     let config = Config::default(); | ||||||
|     let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, NoDma, NoDma, config); |     let irq = interrupt::take!(UART7); | ||||||
|  |     let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, irq, NoDma, NoDma, config); | ||||||
| 
 | 
 | ||||||
|     unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n")); |     unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n")); | ||||||
|     info!("wrote Hello, starting echo"); |     info!("wrote Hello, starting echo"); | ||||||
|  | |||||||
| @ -8,6 +8,7 @@ use cortex_m_rt::entry; | |||||||
| use defmt::*; | use defmt::*; | ||||||
| use embassy_executor::Executor; | use embassy_executor::Executor; | ||||||
| use embassy_stm32::dma::NoDma; | use embassy_stm32::dma::NoDma; | ||||||
|  | use embassy_stm32::interrupt; | ||||||
| use embassy_stm32::usart::{Config, Uart}; | use embassy_stm32::usart::{Config, Uart}; | ||||||
| use heapless::String; | use heapless::String; | ||||||
| use static_cell::StaticCell; | use static_cell::StaticCell; | ||||||
| @ -18,7 +19,8 @@ async fn main_task() { | |||||||
|     let p = embassy_stm32::init(Default::default()); |     let p = embassy_stm32::init(Default::default()); | ||||||
| 
 | 
 | ||||||
|     let config = Config::default(); |     let config = Config::default(); | ||||||
|     let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, p.DMA1_CH0, NoDma, config); |     let irq = interrupt::take!(UART7); | ||||||
|  |     let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, irq, p.DMA1_CH0, NoDma, config); | ||||||
| 
 | 
 | ||||||
|     for n in 0u32.. { |     for n in 0u32.. { | ||||||
|         let mut s: String<128> = String::new(); |         let mut s: String<128> = String::new(); | ||||||
|  | |||||||
| @ -5,6 +5,7 @@ | |||||||
| use defmt::*; | use defmt::*; | ||||||
| use embassy_executor::Spawner; | use embassy_executor::Spawner; | ||||||
| use embassy_stm32::dma::NoDma; | use embassy_stm32::dma::NoDma; | ||||||
|  | use embassy_stm32::interrupt; | ||||||
| use embassy_stm32::peripherals::{DMA1_CH1, UART7}; | use embassy_stm32::peripherals::{DMA1_CH1, UART7}; | ||||||
| use embassy_stm32::usart::{Config, Uart, UartRx}; | use embassy_stm32::usart::{Config, Uart, UartRx}; | ||||||
| use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; | use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; | ||||||
| @ -31,7 +32,8 @@ async fn main(spawner: Spawner) -> ! { | |||||||
|     info!("Hello World!"); |     info!("Hello World!"); | ||||||
| 
 | 
 | ||||||
|     let config = Config::default(); |     let config = Config::default(); | ||||||
|     let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, p.DMA1_CH0, p.DMA1_CH1, config); |     let irq = interrupt::take!(UART7); | ||||||
|  |     let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, irq, p.DMA1_CH0, p.DMA1_CH1, config); | ||||||
|     unwrap!(usart.blocking_write(b"Type 8 chars to echo!\r\n")); |     unwrap!(usart.blocking_write(b"Type 8 chars to echo!\r\n")); | ||||||
| 
 | 
 | ||||||
|     let (mut tx, rx) = usart.split(); |     let (mut tx, rx) = usart.split(); | ||||||
|  | |||||||
| @ -4,13 +4,15 @@ | |||||||
| 
 | 
 | ||||||
| use defmt::*; | use defmt::*; | ||||||
| use embassy_executor::Spawner; | use embassy_executor::Spawner; | ||||||
|  | use embassy_stm32::interrupt; | ||||||
| use embassy_stm32::usart::{Config, Uart}; | use embassy_stm32::usart::{Config, Uart}; | ||||||
| use {defmt_rtt as _, panic_probe as _}; | use {defmt_rtt as _, panic_probe as _}; | ||||||
| 
 | 
 | ||||||
| #[embassy_executor::main] | #[embassy_executor::main] | ||||||
| async fn main(_spawner: Spawner) { | async fn main(_spawner: Spawner) { | ||||||
|     let p = embassy_stm32::init(Default::default()); |     let p = embassy_stm32::init(Default::default()); | ||||||
|     let mut usart = Uart::new(p.USART1, p.PB7, p.PB6, p.DMA1_CH2, p.DMA1_CH3, Config::default()); |     let irq = interrupt::take!(USART1); | ||||||
|  |     let mut usart = Uart::new(p.USART1, p.PB7, p.PB6, irq, p.DMA1_CH2, p.DMA1_CH3, Config::default()); | ||||||
| 
 | 
 | ||||||
|     usart.write(b"Hello Embassy World!\r\n").await.unwrap(); |     usart.write(b"Hello Embassy World!\r\n").await.unwrap(); | ||||||
|     info!("wrote Hello, starting echo"); |     info!("wrote Hello, starting echo"); | ||||||
|  | |||||||
| @ -4,9 +4,8 @@ | |||||||
| 
 | 
 | ||||||
| use defmt::*; | use defmt::*; | ||||||
| use embassy_executor::Spawner; | use embassy_executor::Spawner; | ||||||
| use embassy_stm32::dma::NoDma; |  | ||||||
| use embassy_stm32::interrupt; | use embassy_stm32::interrupt; | ||||||
| use embassy_stm32::usart::{BufferedUart, Config, State, Uart}; | use embassy_stm32::usart::{BufferedUart, Config, State}; | ||||||
| use embedded_io::asynch::{Read, Write}; | use embedded_io::asynch::{Read, Write}; | ||||||
| use {defmt_rtt as _, panic_probe as _}; | use {defmt_rtt as _, panic_probe as _}; | ||||||
| 
 | 
 | ||||||
| @ -21,15 +20,18 @@ async fn main(_spawner: Spawner) { | |||||||
|     let mut config = Config::default(); |     let mut config = Config::default(); | ||||||
|     config.baudrate = 9600; |     config.baudrate = 9600; | ||||||
| 
 | 
 | ||||||
|     let usart = Uart::new(p.USART2, p.PA3, p.PA2, NoDma, NoDma, config); |  | ||||||
|     let mut state = State::new(); |     let mut state = State::new(); | ||||||
|  |     let irq = interrupt::take!(USART2); | ||||||
|     let mut usart = unsafe { |     let mut usart = unsafe { | ||||||
|         BufferedUart::new( |         BufferedUart::new( | ||||||
|             &mut state, |             &mut state, | ||||||
|             usart, |             p.USART2, | ||||||
|             interrupt::take!(USART2), |             p.PA3, | ||||||
|  |             p.PA2, | ||||||
|  |             irq, | ||||||
|             &mut TX_BUFFER, |             &mut TX_BUFFER, | ||||||
|             &mut RX_BUFFER, |             &mut RX_BUFFER, | ||||||
|  |             config, | ||||||
|         ) |         ) | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -4,6 +4,7 @@ | |||||||
| 
 | 
 | ||||||
| use defmt::*; | use defmt::*; | ||||||
| use embassy_stm32::dma::NoDma; | use embassy_stm32::dma::NoDma; | ||||||
|  | use embassy_stm32::interrupt; | ||||||
| use embassy_stm32::usart::{Config, Uart}; | use embassy_stm32::usart::{Config, Uart}; | ||||||
| use {defmt_rtt as _, panic_probe as _}; | use {defmt_rtt as _, panic_probe as _}; | ||||||
| 
 | 
 | ||||||
| @ -14,7 +15,8 @@ fn main() -> ! { | |||||||
|     let p = embassy_stm32::init(Default::default()); |     let p = embassy_stm32::init(Default::default()); | ||||||
| 
 | 
 | ||||||
|     let config = Config::default(); |     let config = Config::default(); | ||||||
|     let mut usart = Uart::new(p.UART4, p.PA1, p.PA0, NoDma, NoDma, config); |     let irq = interrupt::take!(UART4); | ||||||
|  |     let mut usart = Uart::new(p.UART4, p.PA1, p.PA0, irq, NoDma, NoDma, config); | ||||||
| 
 | 
 | ||||||
|     unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n")); |     unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n")); | ||||||
|     info!("wrote Hello, starting echo"); |     info!("wrote Hello, starting echo"); | ||||||
|  | |||||||
| @ -7,6 +7,7 @@ use core::fmt::Write; | |||||||
| use defmt::*; | use defmt::*; | ||||||
| use embassy_executor::Spawner; | use embassy_executor::Spawner; | ||||||
| use embassy_stm32::dma::NoDma; | use embassy_stm32::dma::NoDma; | ||||||
|  | use embassy_stm32::interrupt; | ||||||
| use embassy_stm32::usart::{Config, Uart}; | use embassy_stm32::usart::{Config, Uart}; | ||||||
| use heapless::String; | use heapless::String; | ||||||
| use {defmt_rtt as _, panic_probe as _}; | use {defmt_rtt as _, panic_probe as _}; | ||||||
| @ -17,7 +18,8 @@ async fn main(_spawner: Spawner) { | |||||||
|     info!("Hello World!"); |     info!("Hello World!"); | ||||||
| 
 | 
 | ||||||
|     let config = Config::default(); |     let config = Config::default(); | ||||||
|     let mut usart = Uart::new(p.UART4, p.PA1, p.PA0, p.DMA1_CH3, NoDma, config); |     let irq = interrupt::take!(UART4); | ||||||
|  |     let mut usart = Uart::new(p.UART4, p.PA1, p.PA0, irq, p.DMA1_CH3, NoDma, config); | ||||||
| 
 | 
 | ||||||
|     for n in 0u32.. { |     for n in 0u32.. { | ||||||
|         let mut s: String<128> = String::new(); |         let mut s: String<128> = String::new(); | ||||||
|  | |||||||
| @ -7,6 +7,7 @@ mod example_common; | |||||||
| use defmt::assert_eq; | use defmt::assert_eq; | ||||||
| use embassy_executor::Spawner; | use embassy_executor::Spawner; | ||||||
| use embassy_stm32::dma::NoDma; | use embassy_stm32::dma::NoDma; | ||||||
|  | use embassy_stm32::interrupt; | ||||||
| use embassy_stm32::usart::{Config, Uart}; | use embassy_stm32::usart::{Config, Uart}; | ||||||
| use example_common::*; | use example_common::*; | ||||||
| 
 | 
 | ||||||
| @ -18,22 +19,22 @@ async fn main(_spawner: Spawner) { | |||||||
|     // Arduino pins D0 and D1
 |     // Arduino pins D0 and D1
 | ||||||
|     // They're connected together with a 1K resistor.
 |     // They're connected together with a 1K resistor.
 | ||||||
|     #[cfg(feature = "stm32f103c8")] |     #[cfg(feature = "stm32f103c8")] | ||||||
|     let (tx, rx, usart) = (p.PA9, p.PA10, p.USART1); |     let (tx, rx, usart, irq) = (p.PA9, p.PA10, p.USART1, interrupt::take!(USART1)); | ||||||
|     #[cfg(feature = "stm32g491re")] |     #[cfg(feature = "stm32g491re")] | ||||||
|     let (tx, rx, usart) = (p.PC4, p.PC5, p.USART1); |     let (tx, rx, usart, irq) = (p.PC4, p.PC5, p.USART1, interrupt::take!(USART1)); | ||||||
|     #[cfg(feature = "stm32g071rb")] |     #[cfg(feature = "stm32g071rb")] | ||||||
|     let (tx, rx, usart) = (p.PC4, p.PC5, p.USART1); |     let (tx, rx, usart, irq) = (p.PC4, p.PC5, p.USART1, interrupt::take!(USART1)); | ||||||
|     #[cfg(feature = "stm32f429zi")] |     #[cfg(feature = "stm32f429zi")] | ||||||
|     let (tx, rx, usart) = (p.PG14, p.PG9, p.USART6); |     let (tx, rx, usart, irq) = (p.PG14, p.PG9, p.USART6, interrupt::take!(USART6)); | ||||||
|     #[cfg(feature = "stm32wb55rg")] |     #[cfg(feature = "stm32wb55rg")] | ||||||
|     let (tx, rx, usart) = (p.PA2, p.PA3, p.LPUART1); |     let (tx, rx, usart, irq) = (p.PA2, p.PA3, p.LPUART1, interrupt::take!(LPUART1)); | ||||||
|     #[cfg(feature = "stm32h755zi")] |     #[cfg(feature = "stm32h755zi")] | ||||||
|     let (tx, rx, usart) = (p.PB6, p.PB7, p.USART1); |     let (tx, rx, usart, irq) = (p.PB6, p.PB7, p.USART1, interrupt::take!(USART1)); | ||||||
|     #[cfg(feature = "stm32u585ai")] |     #[cfg(feature = "stm32u585ai")] | ||||||
|     let (tx, rx, usart) = (p.PD8, p.PD9, p.USART3); |     let (tx, rx, usart, irq) = (p.PD8, p.PD9, p.USART3, interrupt::take!(USART3)); | ||||||
| 
 | 
 | ||||||
|     let config = Config::default(); |     let config = Config::default(); | ||||||
|     let mut usart = Uart::new(usart, rx, tx, NoDma, NoDma, config); |     let mut usart = Uart::new(usart, rx, tx, irq, NoDma, NoDma, config); | ||||||
| 
 | 
 | ||||||
|     // We can't send too many bytes, they have to fit in the FIFO.
 |     // We can't send too many bytes, they have to fit in the FIFO.
 | ||||||
|     // This is because we aren't sending+receiving at the same time.
 |     // This is because we aren't sending+receiving at the same time.
 | ||||||
|  | |||||||
| @ -6,6 +6,7 @@ | |||||||
| mod example_common; | mod example_common; | ||||||
| use defmt::assert_eq; | use defmt::assert_eq; | ||||||
| use embassy_executor::Spawner; | use embassy_executor::Spawner; | ||||||
|  | use embassy_stm32::interrupt; | ||||||
| use embassy_stm32::usart::{Config, Uart}; | use embassy_stm32::usart::{Config, Uart}; | ||||||
| use example_common::*; | use example_common::*; | ||||||
| 
 | 
 | ||||||
| @ -17,22 +18,53 @@ async fn main(_spawner: Spawner) { | |||||||
|     // Arduino pins D0 and D1
 |     // Arduino pins D0 and D1
 | ||||||
|     // They're connected together with a 1K resistor.
 |     // They're connected together with a 1K resistor.
 | ||||||
|     #[cfg(feature = "stm32f103c8")] |     #[cfg(feature = "stm32f103c8")] | ||||||
|     let (tx, rx, usart, tx_dma, rx_dma) = (p.PA9, p.PA10, p.USART1, p.DMA1_CH4, p.DMA1_CH5); |     let (tx, rx, usart, irq, tx_dma, rx_dma) = ( | ||||||
|  |         p.PA9, | ||||||
|  |         p.PA10, | ||||||
|  |         p.USART1, | ||||||
|  |         interrupt::take!(USART1), | ||||||
|  |         p.DMA1_CH4, | ||||||
|  |         p.DMA1_CH5, | ||||||
|  |     ); | ||||||
|     #[cfg(feature = "stm32g491re")] |     #[cfg(feature = "stm32g491re")] | ||||||
|     let (tx, rx, usart, tx_dma, rx_dma) = (p.PC4, p.PC5, p.USART1, p.DMA1_CH1, p.DMA1_CH2); |     let (tx, rx, usart, irq, tx_dma, rx_dma) = | ||||||
|  |         (p.PC4, p.PC5, p.USART1, interrupt::take!(USART1), p.DMA1_CH1, p.DMA1_CH2); | ||||||
|     #[cfg(feature = "stm32g071rb")] |     #[cfg(feature = "stm32g071rb")] | ||||||
|     let (tx, rx, usart, tx_dma, rx_dma) = (p.PC4, p.PC5, p.USART1, p.DMA1_CH1, p.DMA1_CH2); |     let (tx, rx, usart, irq, tx_dma, rx_dma) = | ||||||
|  |         (p.PC4, p.PC5, p.USART1, interrupt::take!(USART1), p.DMA1_CH1, p.DMA1_CH2); | ||||||
|     #[cfg(feature = "stm32f429zi")] |     #[cfg(feature = "stm32f429zi")] | ||||||
|     let (tx, rx, usart, tx_dma, rx_dma) = (p.PG14, p.PG9, p.USART6, p.DMA2_CH6, p.DMA2_CH1); |     let (tx, rx, usart, irq, tx_dma, rx_dma) = ( | ||||||
|  |         p.PG14, | ||||||
|  |         p.PG9, | ||||||
|  |         p.USART6, | ||||||
|  |         interrupt::take!(USART6), | ||||||
|  |         p.DMA2_CH6, | ||||||
|  |         p.DMA2_CH1, | ||||||
|  |     ); | ||||||
|     #[cfg(feature = "stm32wb55rg")] |     #[cfg(feature = "stm32wb55rg")] | ||||||
|     let (tx, rx, usart, tx_dma, rx_dma) = (p.PA2, p.PA3, p.LPUART1, p.DMA1_CH1, p.DMA1_CH2); |     let (tx, rx, usart, irq, tx_dma, rx_dma) = ( | ||||||
|  |         p.PA2, | ||||||
|  |         p.PA3, | ||||||
|  |         p.LPUART1, | ||||||
|  |         interrupt::take!(LPUART1), | ||||||
|  |         p.DMA1_CH1, | ||||||
|  |         p.DMA1_CH2, | ||||||
|  |     ); | ||||||
|     #[cfg(feature = "stm32h755zi")] |     #[cfg(feature = "stm32h755zi")] | ||||||
|     let (tx, rx, usart, tx_dma, rx_dma) = (p.PB6, p.PB7, p.USART1, p.DMA1_CH0, p.DMA1_CH1); |     let (tx, rx, usart, irq, tx_dma, rx_dma) = | ||||||
|  |         (p.PB6, p.PB7, p.USART1, interrupt::take!(USART1), p.DMA1_CH0, p.DMA1_CH1); | ||||||
|     #[cfg(feature = "stm32u585ai")] |     #[cfg(feature = "stm32u585ai")] | ||||||
|     let (tx, rx, usart, tx_dma, rx_dma) = (p.PD8, p.PD9, p.USART3, p.GPDMA1_CH0, p.GPDMA1_CH1); |     let (tx, rx, usart, irq, tx_dma, rx_dma) = ( | ||||||
|  |         p.PD8, | ||||||
|  |         p.PD9, | ||||||
|  |         p.USART3, | ||||||
|  |         interrupt::take!(USART3), | ||||||
|  |         p.GPDMA1_CH0, | ||||||
|  |         p.GPDMA1_CH1, | ||||||
|  |     ); | ||||||
| 
 | 
 | ||||||
|     let config = Config::default(); |     let config = Config::default(); | ||||||
|     let mut usart = Uart::new(usart, rx, tx, tx_dma, rx_dma, config); |     let mut usart = Uart::new(usart, rx, tx, irq, tx_dma, rx_dma, config); | ||||||
| 
 | 
 | ||||||
|     // We can't send too many bytes, they have to fit in the FIFO.
 |     // We can't send too many bytes, they have to fit in the FIFO.
 | ||||||
|     // This is because we aren't sending+receiving at the same time.
 |     // This is because we aren't sending+receiving at the same time.
 | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user