diff options
| author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2022-10-26 17:16:15 +0000 |
|---|---|---|
| committer | GitHub <[email protected]> | 2022-10-26 17:16:15 +0000 |
| commit | 9b86de770bccfe00ceaa6b88c51bcaba2a57eb03 (patch) | |
| tree | 91b07477910a4908867e6125a76dea9a587a2360 | |
| parent | ff76fde299d20c9a3f51a3b89ed69761a2531784 (diff) | |
| parent | 9cac649fcf5a633a89aa1b6e550d641270d14956 (diff) | |
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 <[email protected]>
| -rw-r--r-- | embassy-stm32/src/usart/buffered.rs | 34 | ||||
| -rw-r--r-- | embassy-stm32/src/usart/mod.rs | 402 | ||||
| -rw-r--r-- | examples/stm32f3/src/bin/usart_dma.rs | 4 | ||||
| -rw-r--r-- | examples/stm32f4/src/bin/usart.rs | 4 | ||||
| -rw-r--r-- | examples/stm32f4/src/bin/usart_buffered.rs | 15 | ||||
| -rw-r--r-- | examples/stm32f4/src/bin/usart_dma.rs | 4 | ||||
| -rw-r--r-- | examples/stm32f7/src/bin/usart_dma.rs | 4 | ||||
| -rw-r--r-- | examples/stm32h7/src/bin/usart.rs | 4 | ||||
| -rw-r--r-- | examples/stm32h7/src/bin/usart_dma.rs | 4 | ||||
| -rw-r--r-- | examples/stm32h7/src/bin/usart_split.rs | 4 | ||||
| -rw-r--r-- | examples/stm32l0/src/bin/usart_dma.rs | 4 | ||||
| -rw-r--r-- | examples/stm32l0/src/bin/usart_irq.rs | 12 | ||||
| -rw-r--r-- | examples/stm32l4/src/bin/usart.rs | 4 | ||||
| -rw-r--r-- | examples/stm32l4/src/bin/usart_dma.rs | 4 | ||||
| -rw-r--r-- | tests/stm32/src/bin/usart.rs | 17 | ||||
| -rw-r--r-- | tests/stm32/src/bin/usart_dma.rs | 48 |
16 files changed, 500 insertions, 68 deletions
diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs index c30bbc20a..3be0677bd 100644 --- a/embassy-stm32/src/usart/buffered.rs +++ b/embassy-stm32/src/usart/buffered.rs | |||
| @@ -46,16 +46,44 @@ impl<'d, T: BasicInstance> Unpin for BufferedUart<'d, T> {} | |||
| 46 | impl<'d, T: BasicInstance> BufferedUart<'d, T> { | 46 | impl<'d, T: BasicInstance> BufferedUart<'d, T> { |
| 47 | pub fn new( | 47 | pub fn new( |
| 48 | state: &'d mut State<'d, T>, | 48 | state: &'d mut State<'d, T>, |
| 49 | _uart: Uart<'d, T, NoDma, NoDma>, | 49 | _peri: impl Peripheral<P = T> + 'd, |
| 50 | rx: impl Peripheral<P = impl RxPin<T>> + 'd, | ||
| 51 | tx: impl Peripheral<P = impl TxPin<T>> + 'd, | ||
| 50 | irq: impl Peripheral<P = T::Interrupt> + 'd, | 52 | irq: impl Peripheral<P = T::Interrupt> + 'd, |
| 51 | tx_buffer: &'d mut [u8], | 53 | tx_buffer: &'d mut [u8], |
| 52 | rx_buffer: &'d mut [u8], | 54 | rx_buffer: &'d mut [u8], |
| 55 | config: Config, | ||
| 53 | ) -> BufferedUart<'d, T> { | 56 | ) -> BufferedUart<'d, T> { |
| 54 | into_ref!(irq); | 57 | into_ref!(_peri, rx, tx, irq); |
| 58 | |||
| 59 | T::enable(); | ||
| 60 | T::reset(); | ||
| 55 | 61 | ||
| 56 | let r = T::regs(); | 62 | let r = T::regs(); |
| 63 | |||
| 64 | configure(r, &config, T::frequency(), T::MULTIPLIER); | ||
| 65 | |||
| 57 | unsafe { | 66 | unsafe { |
| 58 | r.cr1().modify(|w| { | 67 | rx.set_as_af(rx.af_num(), AFType::Input); |
| 68 | tx.set_as_af(tx.af_num(), AFType::OutputPushPull); | ||
| 69 | |||
| 70 | r.cr2().write(|_w| {}); | ||
| 71 | r.cr3().write(|_w| {}); | ||
| 72 | r.cr1().write(|w| { | ||
| 73 | w.set_ue(true); | ||
| 74 | w.set_te(true); | ||
| 75 | w.set_re(true); | ||
| 76 | w.set_m0(if config.parity != Parity::ParityNone { | ||
| 77 | vals::M0::BIT9 | ||
| 78 | } else { | ||
| 79 | vals::M0::BIT8 | ||
| 80 | }); | ||
| 81 | w.set_pce(config.parity != Parity::ParityNone); | ||
| 82 | w.set_ps(match config.parity { | ||
| 83 | Parity::ParityOdd => vals::Ps::ODD, | ||
| 84 | Parity::ParityEven => vals::Ps::EVEN, | ||
| 85 | _ => vals::Ps::EVEN, | ||
| 86 | }); | ||
| 59 | w.set_rxneie(true); | 87 | w.set_rxneie(true); |
| 60 | w.set_idleie(true); | 88 | w.set_idleie(true); |
| 61 | }); | 89 | }); |
diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index 3f5b99523..dee466b21 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs | |||
| @@ -1,7 +1,11 @@ | |||
| 1 | #![macro_use] | 1 | #![macro_use] |
| 2 | 2 | ||
| 3 | use core::future::poll_fn; | ||
| 3 | use core::marker::PhantomData; | 4 | use core::marker::PhantomData; |
| 5 | use core::task::Poll; | ||
| 4 | 6 | ||
| 7 | use atomic_polyfill::{compiler_fence, Ordering}; | ||
| 8 | use embassy_cortex_m::interrupt::InterruptExt; | ||
| 5 | use embassy_hal_common::{into_ref, PeripheralRef}; | 9 | use embassy_hal_common::{into_ref, PeripheralRef}; |
| 6 | 10 | ||
| 7 | use crate::dma::NoDma; | 11 | use crate::dma::NoDma; |
| @@ -10,6 +14,7 @@ use crate::gpio::sealed::AFType; | |||
| 10 | use crate::pac::lpuart::{regs, vals, Lpuart as Regs}; | 14 | use crate::pac::lpuart::{regs, vals, Lpuart as Regs}; |
| 11 | #[cfg(not(any(lpuart_v1, lpuart_v2)))] | 15 | #[cfg(not(any(lpuart_v1, lpuart_v2)))] |
| 12 | use crate::pac::usart::{regs, vals, Usart as Regs}; | 16 | use crate::pac::usart::{regs, vals, Usart as Regs}; |
| 17 | use crate::time::Hertz; | ||
| 13 | use crate::{peripherals, Peripheral}; | 18 | use crate::{peripherals, Peripheral}; |
| 14 | 19 | ||
| 15 | #[derive(Clone, Copy, PartialEq, Eq, Debug)] | 20 | #[derive(Clone, Copy, PartialEq, Eq, Debug)] |
| @@ -44,6 +49,10 @@ pub struct Config { | |||
| 44 | pub data_bits: DataBits, | 49 | pub data_bits: DataBits, |
| 45 | pub stop_bits: StopBits, | 50 | pub stop_bits: StopBits, |
| 46 | pub parity: Parity, | 51 | pub parity: Parity, |
| 52 | /// if true, on read-like method, if there is a latent error pending, | ||
| 53 | /// read will abort, the error reported and cleared | ||
| 54 | /// if false, the error is ignored and cleared | ||
| 55 | pub detect_previous_overrun: bool, | ||
| 47 | } | 56 | } |
| 48 | 57 | ||
| 49 | impl Default for Config { | 58 | impl Default for Config { |
| @@ -53,6 +62,8 @@ impl Default for Config { | |||
| 53 | data_bits: DataBits::DataBits8, | 62 | data_bits: DataBits::DataBits8, |
| 54 | stop_bits: StopBits::STOP1, | 63 | stop_bits: StopBits::STOP1, |
| 55 | parity: Parity::ParityNone, | 64 | parity: Parity::ParityNone, |
| 65 | // historical behavior | ||
| 66 | detect_previous_overrun: false, | ||
| 56 | } | 67 | } |
| 57 | } | 68 | } |
| 58 | } | 69 | } |
| @@ -70,10 +81,11 @@ pub enum Error { | |||
| 70 | Overrun, | 81 | Overrun, |
| 71 | /// Parity check error | 82 | /// Parity check error |
| 72 | Parity, | 83 | Parity, |
| 84 | /// Buffer too large for DMA | ||
| 85 | BufferTooLong, | ||
| 73 | } | 86 | } |
| 74 | 87 | ||
| 75 | pub struct Uart<'d, T: BasicInstance, TxDma = NoDma, RxDma = NoDma> { | 88 | pub struct Uart<'d, T: BasicInstance, TxDma = NoDma, RxDma = NoDma> { |
| 76 | phantom: PhantomData<&'d mut T>, | ||
| 77 | tx: UartTx<'d, T, TxDma>, | 89 | tx: UartTx<'d, T, TxDma>, |
| 78 | rx: UartRx<'d, T, RxDma>, | 90 | rx: UartRx<'d, T, RxDma>, |
| 79 | } | 91 | } |
| @@ -84,8 +96,9 @@ pub struct UartTx<'d, T: BasicInstance, TxDma = NoDma> { | |||
| 84 | } | 96 | } |
| 85 | 97 | ||
| 86 | pub struct UartRx<'d, T: BasicInstance, RxDma = NoDma> { | 98 | pub struct UartRx<'d, T: BasicInstance, RxDma = NoDma> { |
| 87 | phantom: PhantomData<&'d mut T>, | 99 | _peri: PeripheralRef<'d, T>, |
| 88 | rx_dma: PeripheralRef<'d, RxDma>, | 100 | rx_dma: PeripheralRef<'d, RxDma>, |
| 101 | detect_previous_overrun: bool, | ||
| 89 | } | 102 | } |
| 90 | 103 | ||
| 91 | impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> { | 104 | impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> { |
| @@ -135,10 +148,112 @@ impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> { | |||
| 135 | } | 148 | } |
| 136 | 149 | ||
| 137 | impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> { | 150 | impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> { |
| 138 | fn new(rx_dma: PeripheralRef<'d, RxDma>) -> Self { | 151 | /// usefull if you only want Uart Rx. It saves 1 pin and consumes a little less power |
| 152 | pub fn new( | ||
| 153 | peri: impl Peripheral<P = T> + 'd, | ||
| 154 | irq: impl Peripheral<P = T::Interrupt> + 'd, | ||
| 155 | rx: impl Peripheral<P = impl RxPin<T>> + 'd, | ||
| 156 | rx_dma: impl Peripheral<P = RxDma> + 'd, | ||
| 157 | config: Config, | ||
| 158 | ) -> Self { | ||
| 159 | into_ref!(peri, irq, rx, rx_dma); | ||
| 160 | |||
| 161 | T::enable(); | ||
| 162 | T::reset(); | ||
| 163 | |||
| 164 | let r = T::regs(); | ||
| 165 | |||
| 166 | configure(r, &config, T::frequency(), T::MULTIPLIER); | ||
| 167 | |||
| 168 | unsafe { | ||
| 169 | rx.set_as_af(rx.af_num(), AFType::Input); | ||
| 170 | |||
| 171 | r.cr2().write(|_w| {}); | ||
| 172 | r.cr3().write(|w| { | ||
| 173 | // enable Error Interrupt: (Frame error, Noise error, Overrun error) | ||
| 174 | w.set_eie(true); | ||
| 175 | }); | ||
| 176 | r.cr1().write(|w| { | ||
| 177 | // enable uart | ||
| 178 | w.set_ue(true); | ||
| 179 | // enable receiver | ||
| 180 | w.set_re(true); | ||
| 181 | // configure word size | ||
| 182 | w.set_m0(if config.parity != Parity::ParityNone { | ||
| 183 | vals::M0::BIT9 | ||
| 184 | } else { | ||
| 185 | vals::M0::BIT8 | ||
| 186 | }); | ||
| 187 | // configure parity | ||
| 188 | w.set_pce(config.parity != Parity::ParityNone); | ||
| 189 | w.set_ps(match config.parity { | ||
| 190 | Parity::ParityOdd => vals::Ps::ODD, | ||
| 191 | Parity::ParityEven => vals::Ps::EVEN, | ||
| 192 | _ => vals::Ps::EVEN, | ||
| 193 | }); | ||
| 194 | }); | ||
| 195 | } | ||
| 196 | |||
| 197 | irq.set_handler(Self::on_interrupt); | ||
| 198 | irq.unpend(); | ||
| 199 | irq.enable(); | ||
| 200 | |||
| 201 | // create state once! | ||
| 202 | let _s = T::state(); | ||
| 203 | |||
| 139 | Self { | 204 | Self { |
| 205 | _peri: peri, | ||
| 140 | rx_dma, | 206 | rx_dma, |
| 141 | phantom: PhantomData, | 207 | detect_previous_overrun: config.detect_previous_overrun, |
| 208 | } | ||
| 209 | } | ||
| 210 | |||
| 211 | fn on_interrupt(_: *mut ()) { | ||
| 212 | let r = T::regs(); | ||
| 213 | let s = T::state(); | ||
| 214 | |||
| 215 | let (sr, cr1, cr3) = unsafe { (sr(r).read(), r.cr1().read(), r.cr3().read()) }; | ||
| 216 | |||
| 217 | let has_errors = (sr.pe() && cr1.peie()) || ((sr.fe() || sr.ne() || sr.ore()) && cr3.eie()); | ||
| 218 | |||
| 219 | if has_errors { | ||
| 220 | // clear all interrupts and DMA Rx Request | ||
| 221 | unsafe { | ||
| 222 | r.cr1().modify(|w| { | ||
| 223 | // disable RXNE interrupt | ||
| 224 | w.set_rxneie(false); | ||
| 225 | // disable parity interrupt | ||
| 226 | w.set_peie(false); | ||
| 227 | // disable idle line interrupt | ||
| 228 | w.set_idleie(false); | ||
| 229 | }); | ||
| 230 | r.cr3().modify(|w| { | ||
| 231 | // disable Error Interrupt: (Frame error, Noise error, Overrun error) | ||
| 232 | w.set_eie(false); | ||
| 233 | // disable DMA Rx Request | ||
| 234 | w.set_dmar(false); | ||
| 235 | }); | ||
| 236 | } | ||
| 237 | |||
| 238 | compiler_fence(Ordering::SeqCst); | ||
| 239 | |||
| 240 | s.rx_waker.wake(); | ||
| 241 | } else if cr1.idleie() && sr.idle() { | ||
| 242 | // IDLE detected: no more data will come | ||
| 243 | unsafe { | ||
| 244 | r.cr1().modify(|w| { | ||
| 245 | // disable idle line detection | ||
| 246 | w.set_idleie(false); | ||
| 247 | }); | ||
| 248 | |||
| 249 | r.cr3().modify(|w| { | ||
| 250 | // disable DMA Rx Request | ||
| 251 | w.set_dmar(false); | ||
| 252 | }); | ||
| 253 | } | ||
| 254 | compiler_fence(Ordering::SeqCst); | ||
| 255 | |||
| 256 | s.rx_waker.wake(); | ||
| 142 | } | 257 | } |
| 143 | } | 258 | } |
| 144 | 259 | ||
| @@ -146,17 +261,8 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> { | |||
| 146 | where | 261 | where |
| 147 | RxDma: crate::usart::RxDma<T>, | 262 | RxDma: crate::usart::RxDma<T>, |
| 148 | { | 263 | { |
| 149 | let ch = &mut self.rx_dma; | 264 | self.inner_read(buffer, false).await?; |
| 150 | let request = ch.request(); | 265 | |
| 151 | unsafe { | ||
| 152 | T::regs().cr3().modify(|reg| { | ||
| 153 | reg.set_dmar(true); | ||
| 154 | }); | ||
| 155 | } | ||
| 156 | // If we don't assign future to a variable, the data register pointer | ||
| 157 | // is held across an await and makes the future non-Send. | ||
| 158 | let transfer = crate::dma::read(ch, request, rdr(T::regs()), buffer); | ||
| 159 | transfer.await; | ||
| 160 | Ok(()) | 266 | Ok(()) |
| 161 | } | 267 | } |
| 162 | 268 | ||
| @@ -211,13 +317,202 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> { | |||
| 211 | } | 317 | } |
| 212 | Ok(()) | 318 | Ok(()) |
| 213 | } | 319 | } |
| 320 | |||
| 321 | pub async fn read_until_idle(&mut self, buffer: &mut [u8]) -> Result<usize, Error> | ||
| 322 | where | ||
| 323 | RxDma: crate::usart::RxDma<T>, | ||
| 324 | { | ||
| 325 | self.inner_read(buffer, true).await | ||
| 326 | } | ||
| 327 | |||
| 328 | async fn inner_read(&mut self, buffer: &mut [u8], enable_idle_line_detection: bool) -> Result<usize, Error> | ||
| 329 | where | ||
| 330 | RxDma: crate::usart::RxDma<T>, | ||
| 331 | { | ||
| 332 | if buffer.is_empty() { | ||
| 333 | return Ok(0); | ||
| 334 | } else if buffer.len() > 0xFFFF { | ||
| 335 | return Err(Error::BufferTooLong); | ||
| 336 | } | ||
| 337 | |||
| 338 | let r = T::regs(); | ||
| 339 | |||
| 340 | let buffer_len = buffer.len(); | ||
| 341 | |||
| 342 | let ch = &mut self.rx_dma; | ||
| 343 | let request = ch.request(); | ||
| 344 | |||
| 345 | // SAFETY: The only way we might have a problem is using split rx and tx | ||
| 346 | // here we only modify or read Rx related flags, interrupts and DMA channel | ||
| 347 | unsafe { | ||
| 348 | // Start USART DMA | ||
| 349 | // will not do anything yet because DMAR is not yet set | ||
| 350 | ch.start_read(request, rdr(r), buffer, Default::default()); | ||
| 351 | |||
| 352 | // clear ORE flag just before enabling DMA Rx Request: can be mandatory for the second transfer | ||
| 353 | if !self.detect_previous_overrun { | ||
| 354 | let sr = sr(r).read(); | ||
| 355 | // This read also clears the error and idle interrupt flags on v1. | ||
| 356 | rdr(r).read_volatile(); | ||
| 357 | clear_interrupt_flags(r, sr); | ||
| 358 | } | ||
| 359 | |||
| 360 | r.cr1().modify(|w| { | ||
| 361 | // disable RXNE interrupt | ||
| 362 | w.set_rxneie(false); | ||
| 363 | // enable parity interrupt if not ParityNone | ||
| 364 | w.set_peie(w.pce()); | ||
| 365 | }); | ||
| 366 | |||
| 367 | r.cr3().modify(|w| { | ||
| 368 | // enable Error Interrupt: (Frame error, Noise error, Overrun error) | ||
| 369 | w.set_eie(true); | ||
| 370 | // enable DMA Rx Request | ||
| 371 | w.set_dmar(true); | ||
| 372 | }); | ||
| 373 | |||
| 374 | compiler_fence(Ordering::SeqCst); | ||
| 375 | |||
| 376 | // In case of errors already pending when reception started, interrupts may have already been raised | ||
| 377 | // and lead to reception abortion (Overrun error for instance). In such a case, all interrupts | ||
| 378 | // have been disabled in interrupt handler and DMA Rx Request has been disabled. | ||
| 379 | |||
| 380 | let cr3 = r.cr3().read(); | ||
| 381 | |||
| 382 | if !cr3.dmar() { | ||
| 383 | // something went wrong | ||
| 384 | // because the only way to get this flag cleared is to have an interrupt | ||
| 385 | |||
| 386 | // abort DMA transfer | ||
| 387 | ch.request_stop(); | ||
| 388 | while ch.is_running() {} | ||
| 389 | |||
| 390 | let sr = sr(r).read(); | ||
| 391 | // This read also clears the error and idle interrupt flags on v1. | ||
| 392 | rdr(r).read_volatile(); | ||
| 393 | clear_interrupt_flags(r, sr); | ||
| 394 | |||
| 395 | if sr.pe() { | ||
| 396 | return Err(Error::Parity); | ||
| 397 | } | ||
| 398 | if sr.fe() { | ||
| 399 | return Err(Error::Framing); | ||
| 400 | } | ||
| 401 | if sr.ne() { | ||
| 402 | return Err(Error::Noise); | ||
| 403 | } | ||
| 404 | if sr.ore() { | ||
| 405 | return Err(Error::Overrun); | ||
| 406 | } | ||
| 407 | |||
| 408 | unreachable!(); | ||
| 409 | } | ||
| 410 | |||
| 411 | // clear idle flag | ||
| 412 | if enable_idle_line_detection { | ||
| 413 | let sr = sr(r).read(); | ||
| 414 | // This read also clears the error and idle interrupt flags on v1. | ||
| 415 | rdr(r).read_volatile(); | ||
| 416 | clear_interrupt_flags(r, sr); | ||
| 417 | |||
| 418 | // enable idle interrupt | ||
| 419 | r.cr1().modify(|w| { | ||
| 420 | w.set_idleie(true); | ||
| 421 | }); | ||
| 422 | } | ||
| 423 | } | ||
| 424 | |||
| 425 | compiler_fence(Ordering::SeqCst); | ||
| 426 | |||
| 427 | let res = poll_fn(move |cx| { | ||
| 428 | let s = T::state(); | ||
| 429 | |||
| 430 | ch.set_waker(cx.waker()); | ||
| 431 | s.rx_waker.register(cx.waker()); | ||
| 432 | |||
| 433 | // SAFETY: read only and we only use Rx related flags | ||
| 434 | let sr = unsafe { sr(r).read() }; | ||
| 435 | |||
| 436 | // SAFETY: only clears Rx related flags | ||
| 437 | unsafe { | ||
| 438 | // This read also clears the error and idle interrupt flags on v1. | ||
| 439 | rdr(r).read_volatile(); | ||
| 440 | clear_interrupt_flags(r, sr); | ||
| 441 | } | ||
| 442 | |||
| 443 | compiler_fence(Ordering::SeqCst); | ||
| 444 | |||
| 445 | let has_errors = sr.pe() || sr.fe() || sr.ne() || sr.ore(); | ||
| 446 | |||
| 447 | if has_errors { | ||
| 448 | // all Rx interrupts and Rx DMA Request have already been cleared in interrupt handler | ||
| 449 | |||
| 450 | // stop dma transfer | ||
| 451 | ch.request_stop(); | ||
| 452 | while ch.is_running() {} | ||
| 453 | |||
| 454 | if sr.pe() { | ||
| 455 | return Poll::Ready(Err(Error::Parity)); | ||
| 456 | } | ||
| 457 | if sr.fe() { | ||
| 458 | return Poll::Ready(Err(Error::Framing)); | ||
| 459 | } | ||
| 460 | if sr.ne() { | ||
| 461 | return Poll::Ready(Err(Error::Noise)); | ||
| 462 | } | ||
| 463 | if sr.ore() { | ||
| 464 | return Poll::Ready(Err(Error::Overrun)); | ||
| 465 | } | ||
| 466 | } | ||
| 467 | |||
| 468 | if sr.idle() { | ||
| 469 | // Idle line | ||
| 470 | |||
| 471 | // stop dma transfer | ||
| 472 | ch.request_stop(); | ||
| 473 | while ch.is_running() {} | ||
| 474 | |||
| 475 | let n = buffer_len - (ch.remaining_transfers() as usize); | ||
| 476 | |||
| 477 | return Poll::Ready(Ok(n)); | ||
| 478 | } else if !ch.is_running() { | ||
| 479 | // DMA complete | ||
| 480 | return Poll::Ready(Ok(buffer_len)); | ||
| 481 | } | ||
| 482 | |||
| 483 | Poll::Pending | ||
| 484 | }) | ||
| 485 | .await; | ||
| 486 | |||
| 487 | // clear all interrupts and DMA Rx Request | ||
| 488 | // SAFETY: only clears Rx related flags | ||
| 489 | unsafe { | ||
| 490 | r.cr1().modify(|w| { | ||
| 491 | // disable RXNE interrupt | ||
| 492 | w.set_rxneie(false); | ||
| 493 | // disable parity interrupt | ||
| 494 | w.set_peie(false); | ||
| 495 | // disable idle line interrupt | ||
| 496 | w.set_idleie(false); | ||
| 497 | }); | ||
| 498 | r.cr3().modify(|w| { | ||
| 499 | // disable Error Interrupt: (Frame error, Noise error, Overrun error) | ||
| 500 | w.set_eie(false); | ||
| 501 | // disable DMA Rx Request | ||
| 502 | w.set_dmar(false); | ||
| 503 | }); | ||
| 504 | } | ||
| 505 | |||
| 506 | res | ||
| 507 | } | ||
| 214 | } | 508 | } |
| 215 | 509 | ||
| 216 | impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { | 510 | impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { |
| 217 | pub fn new( | 511 | pub fn new( |
| 218 | _inner: impl Peripheral<P = T> + 'd, | 512 | peri: impl Peripheral<P = T> + 'd, |
| 219 | rx: impl Peripheral<P = impl RxPin<T>> + 'd, | 513 | rx: impl Peripheral<P = impl RxPin<T>> + 'd, |
| 220 | tx: impl Peripheral<P = impl TxPin<T>> + 'd, | 514 | tx: impl Peripheral<P = impl TxPin<T>> + 'd, |
| 515 | irq: impl Peripheral<P = T::Interrupt> + 'd, | ||
| 221 | tx_dma: impl Peripheral<P = TxDma> + 'd, | 516 | tx_dma: impl Peripheral<P = TxDma> + 'd, |
| 222 | rx_dma: impl Peripheral<P = RxDma> + 'd, | 517 | rx_dma: impl Peripheral<P = RxDma> + 'd, |
| 223 | config: Config, | 518 | config: Config, |
| @@ -225,13 +520,14 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { | |||
| 225 | T::enable(); | 520 | T::enable(); |
| 226 | T::reset(); | 521 | T::reset(); |
| 227 | 522 | ||
| 228 | Self::new_inner(_inner, rx, tx, tx_dma, rx_dma, config) | 523 | Self::new_inner(peri, rx, tx, irq, tx_dma, rx_dma, config) |
| 229 | } | 524 | } |
| 230 | 525 | ||
| 231 | pub fn new_with_rtscts( | 526 | pub fn new_with_rtscts( |
| 232 | _inner: impl Peripheral<P = T> + 'd, | 527 | peri: impl Peripheral<P = T> + 'd, |
| 233 | rx: impl Peripheral<P = impl RxPin<T>> + 'd, | 528 | rx: impl Peripheral<P = impl RxPin<T>> + 'd, |
| 234 | tx: impl Peripheral<P = impl TxPin<T>> + 'd, | 529 | tx: impl Peripheral<P = impl TxPin<T>> + 'd, |
| 530 | irq: impl Peripheral<P = T::Interrupt> + 'd, | ||
| 235 | rts: impl Peripheral<P = impl RtsPin<T>> + 'd, | 531 | rts: impl Peripheral<P = impl RtsPin<T>> + 'd, |
| 236 | cts: impl Peripheral<P = impl CtsPin<T>> + 'd, | 532 | cts: impl Peripheral<P = impl CtsPin<T>> + 'd, |
| 237 | tx_dma: impl Peripheral<P = TxDma> + 'd, | 533 | tx_dma: impl Peripheral<P = TxDma> + 'd, |
| @@ -251,32 +547,29 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { | |||
| 251 | w.set_ctse(true); | 547 | w.set_ctse(true); |
| 252 | }); | 548 | }); |
| 253 | } | 549 | } |
| 254 | Self::new_inner(_inner, rx, tx, tx_dma, rx_dma, config) | 550 | Self::new_inner(peri, rx, tx, irq, tx_dma, rx_dma, config) |
| 255 | } | 551 | } |
| 256 | 552 | ||
| 257 | fn new_inner( | 553 | fn new_inner( |
| 258 | _inner: impl Peripheral<P = T> + 'd, | 554 | peri: impl Peripheral<P = T> + 'd, |
| 259 | rx: impl Peripheral<P = impl RxPin<T>> + 'd, | 555 | rx: impl Peripheral<P = impl RxPin<T>> + 'd, |
| 260 | tx: impl Peripheral<P = impl TxPin<T>> + 'd, | 556 | tx: impl Peripheral<P = impl TxPin<T>> + 'd, |
| 557 | irq: impl Peripheral<P = T::Interrupt> + 'd, | ||
| 261 | tx_dma: impl Peripheral<P = TxDma> + 'd, | 558 | tx_dma: impl Peripheral<P = TxDma> + 'd, |
| 262 | rx_dma: impl Peripheral<P = RxDma> + 'd, | 559 | rx_dma: impl Peripheral<P = RxDma> + 'd, |
| 263 | config: Config, | 560 | config: Config, |
| 264 | ) -> Self { | 561 | ) -> Self { |
| 265 | into_ref!(_inner, rx, tx, tx_dma, rx_dma); | 562 | into_ref!(peri, rx, tx, irq, tx_dma, rx_dma); |
| 266 | |||
| 267 | let pclk_freq = T::frequency(); | ||
| 268 | |||
| 269 | // TODO: better calculation, including error checking and OVER8 if possible. | ||
| 270 | let div = (pclk_freq.0 + (config.baudrate / 2)) / config.baudrate * T::MULTIPLIER; | ||
| 271 | 563 | ||
| 272 | let r = T::regs(); | 564 | let r = T::regs(); |
| 273 | 565 | ||
| 566 | configure(r, &config, T::frequency(), T::MULTIPLIER); | ||
| 567 | |||
| 274 | unsafe { | 568 | unsafe { |
| 275 | rx.set_as_af(rx.af_num(), AFType::Input); | 569 | rx.set_as_af(rx.af_num(), AFType::Input); |
| 276 | tx.set_as_af(tx.af_num(), AFType::OutputPushPull); | 570 | tx.set_as_af(tx.af_num(), AFType::OutputPushPull); |
| 277 | 571 | ||
| 278 | r.cr2().write(|_w| {}); | 572 | r.cr2().write(|_w| {}); |
| 279 | r.brr().write_value(regs::Brr(div)); | ||
| 280 | r.cr1().write(|w| { | 573 | r.cr1().write(|w| { |
| 281 | w.set_ue(true); | 574 | w.set_ue(true); |
| 282 | w.set_te(true); | 575 | w.set_te(true); |
| @@ -295,10 +588,20 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { | |||
| 295 | }); | 588 | }); |
| 296 | } | 589 | } |
| 297 | 590 | ||
| 591 | irq.set_handler(UartRx::<T, RxDma>::on_interrupt); | ||
| 592 | irq.unpend(); | ||
| 593 | irq.enable(); | ||
| 594 | |||
| 595 | // create state once! | ||
| 596 | let _s = T::state(); | ||
| 597 | |||
| 298 | Self { | 598 | Self { |
| 299 | tx: UartTx::new(tx_dma), | 599 | tx: UartTx::new(tx_dma), |
| 300 | rx: UartRx::new(rx_dma), | 600 | rx: UartRx { |
| 301 | phantom: PhantomData {}, | 601 | _peri: peri, |
| 602 | rx_dma, | ||
| 603 | detect_previous_overrun: config.detect_previous_overrun, | ||
| 604 | }, | ||
| 302 | } | 605 | } |
| 303 | } | 606 | } |
| 304 | 607 | ||
| @@ -332,6 +635,13 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { | |||
| 332 | self.rx.blocking_read(buffer) | 635 | self.rx.blocking_read(buffer) |
| 333 | } | 636 | } |
| 334 | 637 | ||
| 638 | pub async fn read_until_idle(&mut self, buffer: &mut [u8]) -> Result<usize, Error> | ||
| 639 | where | ||
| 640 | RxDma: crate::usart::RxDma<T>, | ||
| 641 | { | ||
| 642 | self.rx.read_until_idle(buffer).await | ||
| 643 | } | ||
| 644 | |||
| 335 | /// Split the Uart into a transmitter and receiver, which is | 645 | /// Split the Uart into a transmitter and receiver, which is |
| 336 | /// particuarly useful when having two tasks correlating to | 646 | /// particuarly useful when having two tasks correlating to |
| 337 | /// transmitting and receiving. | 647 | /// transmitting and receiving. |
| @@ -340,6 +650,15 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { | |||
| 340 | } | 650 | } |
| 341 | } | 651 | } |
| 342 | 652 | ||
| 653 | fn configure(r: Regs, config: &Config, pclk_freq: Hertz, multiplier: u32) { | ||
| 654 | // TODO: better calculation, including error checking and OVER8 if possible. | ||
| 655 | let div = (pclk_freq.0 + (config.baudrate / 2)) / config.baudrate * multiplier; | ||
| 656 | |||
| 657 | unsafe { | ||
| 658 | r.brr().write_value(regs::Brr(div)); | ||
| 659 | } | ||
| 660 | } | ||
| 661 | |||
| 343 | mod eh02 { | 662 | mod eh02 { |
| 344 | use super::*; | 663 | use super::*; |
| 345 | 664 | ||
| @@ -389,6 +708,7 @@ mod eh1 { | |||
| 389 | Self::Noise => embedded_hal_1::serial::ErrorKind::Noise, | 708 | Self::Noise => embedded_hal_1::serial::ErrorKind::Noise, |
| 390 | Self::Overrun => embedded_hal_1::serial::ErrorKind::Overrun, | 709 | Self::Overrun => embedded_hal_1::serial::ErrorKind::Overrun, |
| 391 | Self::Parity => embedded_hal_1::serial::ErrorKind::Parity, | 710 | Self::Parity => embedded_hal_1::serial::ErrorKind::Parity, |
| 711 | Self::BufferTooLong => embedded_hal_1::serial::ErrorKind::Other, | ||
| 392 | } | 712 | } |
| 393 | } | 713 | } |
| 394 | } | 714 | } |
| @@ -573,13 +893,30 @@ unsafe fn clear_interrupt_flags(r: Regs, sr: regs::Isr) { | |||
| 573 | } | 893 | } |
| 574 | 894 | ||
| 575 | pub(crate) mod sealed { | 895 | pub(crate) mod sealed { |
| 896 | use embassy_sync::waitqueue::AtomicWaker; | ||
| 897 | |||
| 576 | use super::*; | 898 | use super::*; |
| 577 | 899 | ||
| 900 | pub struct State { | ||
| 901 | pub rx_waker: AtomicWaker, | ||
| 902 | pub tx_waker: AtomicWaker, | ||
| 903 | } | ||
| 904 | |||
| 905 | impl State { | ||
| 906 | pub const fn new() -> Self { | ||
| 907 | Self { | ||
| 908 | rx_waker: AtomicWaker::new(), | ||
| 909 | tx_waker: AtomicWaker::new(), | ||
| 910 | } | ||
| 911 | } | ||
| 912 | } | ||
| 913 | |||
| 578 | pub trait BasicInstance: crate::rcc::RccPeripheral { | 914 | pub trait BasicInstance: crate::rcc::RccPeripheral { |
| 579 | const MULTIPLIER: u32; | 915 | const MULTIPLIER: u32; |
| 580 | type Interrupt: crate::interrupt::Interrupt; | 916 | type Interrupt: crate::interrupt::Interrupt; |
| 581 | 917 | ||
| 582 | fn regs() -> Regs; | 918 | fn regs() -> Regs; |
| 919 | fn state() -> &'static State; | ||
| 583 | } | 920 | } |
| 584 | 921 | ||
| 585 | pub trait FullInstance: BasicInstance { | 922 | pub trait FullInstance: BasicInstance { |
| @@ -587,7 +924,7 @@ pub(crate) mod sealed { | |||
| 587 | } | 924 | } |
| 588 | } | 925 | } |
| 589 | 926 | ||
| 590 | pub trait BasicInstance: sealed::BasicInstance {} | 927 | pub trait BasicInstance: Peripheral<P = Self> + sealed::BasicInstance + 'static + Send {} |
| 591 | 928 | ||
| 592 | pub trait FullInstance: sealed::FullInstance {} | 929 | pub trait FullInstance: sealed::FullInstance {} |
| 593 | 930 | ||
| @@ -609,6 +946,11 @@ macro_rules! impl_lpuart { | |||
| 609 | fn regs() -> Regs { | 946 | fn regs() -> Regs { |
| 610 | Regs(crate::pac::$inst.0) | 947 | Regs(crate::pac::$inst.0) |
| 611 | } | 948 | } |
| 949 | |||
| 950 | fn state() -> &'static crate::usart::sealed::State { | ||
| 951 | static STATE: crate::usart::sealed::State = crate::usart::sealed::State::new(); | ||
| 952 | &STATE | ||
| 953 | } | ||
| 612 | } | 954 | } |
| 613 | 955 | ||
| 614 | impl BasicInstance for peripherals::$inst {} | 956 | impl BasicInstance for peripherals::$inst {} |
diff --git a/examples/stm32f3/src/bin/usart_dma.rs b/examples/stm32f3/src/bin/usart_dma.rs index 3bc5a287f..47121acf1 100644 --- a/examples/stm32f3/src/bin/usart_dma.rs +++ b/examples/stm32f3/src/bin/usart_dma.rs | |||
| @@ -7,6 +7,7 @@ use core::fmt::Write; | |||
| 7 | use defmt::*; | 7 | use defmt::*; |
| 8 | use embassy_executor::Spawner; | 8 | use embassy_executor::Spawner; |
| 9 | use embassy_stm32::dma::NoDma; | 9 | use embassy_stm32::dma::NoDma; |
| 10 | use embassy_stm32::interrupt; | ||
| 10 | use embassy_stm32::usart::{Config, Uart}; | 11 | use embassy_stm32::usart::{Config, Uart}; |
| 11 | use heapless::String; | 12 | use heapless::String; |
| 12 | use {defmt_rtt as _, panic_probe as _}; | 13 | use {defmt_rtt as _, panic_probe as _}; |
| @@ -17,7 +18,8 @@ async fn main(_spawner: Spawner) { | |||
| 17 | info!("Hello World!"); | 18 | info!("Hello World!"); |
| 18 | 19 | ||
| 19 | let config = Config::default(); | 20 | let config = Config::default(); |
| 20 | let mut usart = Uart::new(p.USART1, p.PE1, p.PE0, p.DMA1_CH4, NoDma, config); | 21 | let irq = interrupt::take!(USART1); |
| 22 | let mut usart = Uart::new(p.USART1, p.PE1, p.PE0, irq, p.DMA1_CH4, NoDma, config); | ||
| 21 | 23 | ||
| 22 | for n in 0u32.. { | 24 | for n in 0u32.. { |
| 23 | let mut s: String<128> = String::new(); | 25 | let mut s: String<128> = String::new(); |
diff --git a/examples/stm32f4/src/bin/usart.rs b/examples/stm32f4/src/bin/usart.rs index 90ad882b8..8f41bb6c4 100644 --- a/examples/stm32f4/src/bin/usart.rs +++ b/examples/stm32f4/src/bin/usart.rs | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | use cortex_m_rt::entry; | 5 | use cortex_m_rt::entry; |
| 6 | use defmt::*; | 6 | use defmt::*; |
| 7 | use embassy_stm32::dma::NoDma; | 7 | use embassy_stm32::dma::NoDma; |
| 8 | use embassy_stm32::interrupt; | ||
| 8 | use embassy_stm32::usart::{Config, Uart}; | 9 | use embassy_stm32::usart::{Config, Uart}; |
| 9 | use {defmt_rtt as _, panic_probe as _}; | 10 | use {defmt_rtt as _, panic_probe as _}; |
| 10 | 11 | ||
| @@ -15,7 +16,8 @@ fn main() -> ! { | |||
| 15 | let p = embassy_stm32::init(Default::default()); | 16 | let p = embassy_stm32::init(Default::default()); |
| 16 | 17 | ||
| 17 | let config = Config::default(); | 18 | let config = Config::default(); |
| 18 | let mut usart = Uart::new(p.USART3, p.PD9, p.PD8, NoDma, NoDma, config); | 19 | let irq = interrupt::take!(USART3); |
| 20 | let mut usart = Uart::new(p.USART3, p.PD9, p.PD8, irq, NoDma, NoDma, config); | ||
| 19 | 21 | ||
| 20 | unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n")); | 22 | unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n")); |
| 21 | info!("wrote Hello, starting echo"); | 23 | info!("wrote Hello, starting echo"); |
diff --git a/examples/stm32f4/src/bin/usart_buffered.rs b/examples/stm32f4/src/bin/usart_buffered.rs index 7bcecbd26..dd171fe13 100644 --- a/examples/stm32f4/src/bin/usart_buffered.rs +++ b/examples/stm32f4/src/bin/usart_buffered.rs | |||
| @@ -4,9 +4,8 @@ | |||
| 4 | 4 | ||
| 5 | use defmt::*; | 5 | use defmt::*; |
| 6 | use embassy_executor::Spawner; | 6 | use embassy_executor::Spawner; |
| 7 | use embassy_stm32::dma::NoDma; | ||
| 8 | use embassy_stm32::interrupt; | 7 | use embassy_stm32::interrupt; |
| 9 | use embassy_stm32::usart::{BufferedUart, Config, State, Uart}; | 8 | use embassy_stm32::usart::{BufferedUart, Config, State}; |
| 10 | use embedded_io::asynch::BufRead; | 9 | use embedded_io::asynch::BufRead; |
| 11 | use {defmt_rtt as _, panic_probe as _}; | 10 | use {defmt_rtt as _, panic_probe as _}; |
| 12 | 11 | ||
| @@ -16,13 +15,21 @@ async fn main(_spawner: Spawner) { | |||
| 16 | info!("Hello World!"); | 15 | info!("Hello World!"); |
| 17 | 16 | ||
| 18 | let config = Config::default(); | 17 | let config = Config::default(); |
| 19 | let usart = Uart::new(p.USART3, p.PD9, p.PD8, NoDma, NoDma, config); | ||
| 20 | 18 | ||
| 21 | let mut state = State::new(); | 19 | let mut state = State::new(); |
| 22 | let irq = interrupt::take!(USART3); | 20 | let irq = interrupt::take!(USART3); |
| 23 | let mut tx_buf = [0u8; 32]; | 21 | let mut tx_buf = [0u8; 32]; |
| 24 | let mut rx_buf = [0u8; 32]; | 22 | let mut rx_buf = [0u8; 32]; |
| 25 | let mut buf_usart = BufferedUart::new(&mut state, usart, irq, &mut tx_buf, &mut rx_buf); | 23 | let mut buf_usart = BufferedUart::new( |
| 24 | &mut state, | ||
| 25 | p.USART3, | ||
| 26 | p.PD9, | ||
| 27 | p.PD8, | ||
| 28 | irq, | ||
| 29 | &mut tx_buf, | ||
| 30 | &mut rx_buf, | ||
| 31 | config, | ||
| 32 | ); | ||
| 26 | 33 | ||
| 27 | loop { | 34 | loop { |
| 28 | let buf = buf_usart.fill_buf().await.unwrap(); | 35 | let buf = buf_usart.fill_buf().await.unwrap(); |
diff --git a/examples/stm32f4/src/bin/usart_dma.rs b/examples/stm32f4/src/bin/usart_dma.rs index bb41b8b4f..78baeaa0d 100644 --- a/examples/stm32f4/src/bin/usart_dma.rs +++ b/examples/stm32f4/src/bin/usart_dma.rs | |||
| @@ -7,6 +7,7 @@ use core::fmt::Write; | |||
| 7 | use defmt::*; | 7 | use defmt::*; |
| 8 | use embassy_executor::Spawner; | 8 | use embassy_executor::Spawner; |
| 9 | use embassy_stm32::dma::NoDma; | 9 | use embassy_stm32::dma::NoDma; |
| 10 | use embassy_stm32::interrupt; | ||
| 10 | use embassy_stm32::usart::{Config, Uart}; | 11 | use embassy_stm32::usart::{Config, Uart}; |
| 11 | use heapless::String; | 12 | use heapless::String; |
| 12 | use {defmt_rtt as _, panic_probe as _}; | 13 | use {defmt_rtt as _, panic_probe as _}; |
| @@ -17,7 +18,8 @@ async fn main(_spawner: Spawner) { | |||
| 17 | info!("Hello World!"); | 18 | info!("Hello World!"); |
| 18 | 19 | ||
| 19 | let config = Config::default(); | 20 | let config = Config::default(); |
| 20 | let mut usart = Uart::new(p.USART3, p.PD9, p.PD8, p.DMA1_CH3, NoDma, config); | 21 | let irq = interrupt::take!(USART3); |
| 22 | let mut usart = Uart::new(p.USART3, p.PD9, p.PD8, irq, p.DMA1_CH3, NoDma, config); | ||
| 21 | 23 | ||
| 22 | for n in 0u32.. { | 24 | for n in 0u32.. { |
| 23 | let mut s: String<128> = String::new(); | 25 | let mut s: String<128> = String::new(); |
diff --git a/examples/stm32f7/src/bin/usart_dma.rs b/examples/stm32f7/src/bin/usart_dma.rs index 07270479c..4827c52ae 100644 --- a/examples/stm32f7/src/bin/usart_dma.rs +++ b/examples/stm32f7/src/bin/usart_dma.rs | |||
| @@ -7,6 +7,7 @@ use core::fmt::Write; | |||
| 7 | use defmt::*; | 7 | use defmt::*; |
| 8 | use embassy_executor::Spawner; | 8 | use embassy_executor::Spawner; |
| 9 | use embassy_stm32::dma::NoDma; | 9 | use embassy_stm32::dma::NoDma; |
| 10 | use embassy_stm32::interrupt; | ||
| 10 | use embassy_stm32::usart::{Config, Uart}; | 11 | use embassy_stm32::usart::{Config, Uart}; |
| 11 | use heapless::String; | 12 | use heapless::String; |
| 12 | use {defmt_rtt as _, panic_probe as _}; | 13 | use {defmt_rtt as _, panic_probe as _}; |
| @@ -15,7 +16,8 @@ use {defmt_rtt as _, panic_probe as _}; | |||
| 15 | async fn main(_spawner: Spawner) { | 16 | async fn main(_spawner: Spawner) { |
| 16 | let p = embassy_stm32::init(Default::default()); | 17 | let p = embassy_stm32::init(Default::default()); |
| 17 | let config = Config::default(); | 18 | let config = Config::default(); |
| 18 | let mut usart = Uart::new(p.UART7, p.PA8, p.PA15, p.DMA1_CH1, NoDma, config); | 19 | let irq = interrupt::take!(UART7); |
| 20 | let mut usart = Uart::new(p.UART7, p.PA8, p.PA15, irq, p.DMA1_CH1, NoDma, config); | ||
| 19 | 21 | ||
| 20 | for n in 0u32.. { | 22 | for n in 0u32.. { |
| 21 | let mut s: String<128> = String::new(); | 23 | let mut s: String<128> = String::new(); |
diff --git a/examples/stm32h7/src/bin/usart.rs b/examples/stm32h7/src/bin/usart.rs index 87c2b1253..405f18ec7 100644 --- a/examples/stm32h7/src/bin/usart.rs +++ b/examples/stm32h7/src/bin/usart.rs | |||
| @@ -6,6 +6,7 @@ use cortex_m_rt::entry; | |||
| 6 | use defmt::*; | 6 | use defmt::*; |
| 7 | use embassy_executor::Executor; | 7 | use embassy_executor::Executor; |
| 8 | use embassy_stm32::dma::NoDma; | 8 | use embassy_stm32::dma::NoDma; |
| 9 | use embassy_stm32::interrupt; | ||
| 9 | use embassy_stm32::usart::{Config, Uart}; | 10 | use embassy_stm32::usart::{Config, Uart}; |
| 10 | use static_cell::StaticCell; | 11 | use static_cell::StaticCell; |
| 11 | use {defmt_rtt as _, panic_probe as _}; | 12 | use {defmt_rtt as _, panic_probe as _}; |
| @@ -15,7 +16,8 @@ async fn main_task() { | |||
| 15 | let p = embassy_stm32::init(Default::default()); | 16 | let p = embassy_stm32::init(Default::default()); |
| 16 | 17 | ||
| 17 | let config = Config::default(); | 18 | let config = Config::default(); |
| 18 | let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, NoDma, NoDma, config); | 19 | let irq = interrupt::take!(UART7); |
| 20 | let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, irq, NoDma, NoDma, config); | ||
| 19 | 21 | ||
| 20 | unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n")); | 22 | unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n")); |
| 21 | info!("wrote Hello, starting echo"); | 23 | info!("wrote Hello, starting echo"); |
diff --git a/examples/stm32h7/src/bin/usart_dma.rs b/examples/stm32h7/src/bin/usart_dma.rs index 3adffcbeb..6e3491e55 100644 --- a/examples/stm32h7/src/bin/usart_dma.rs +++ b/examples/stm32h7/src/bin/usart_dma.rs | |||
| @@ -8,6 +8,7 @@ use cortex_m_rt::entry; | |||
| 8 | use defmt::*; | 8 | use defmt::*; |
| 9 | use embassy_executor::Executor; | 9 | use embassy_executor::Executor; |
| 10 | use embassy_stm32::dma::NoDma; | 10 | use embassy_stm32::dma::NoDma; |
| 11 | use embassy_stm32::interrupt; | ||
| 11 | use embassy_stm32::usart::{Config, Uart}; | 12 | use embassy_stm32::usart::{Config, Uart}; |
| 12 | use heapless::String; | 13 | use heapless::String; |
| 13 | use static_cell::StaticCell; | 14 | use static_cell::StaticCell; |
| @@ -18,7 +19,8 @@ async fn main_task() { | |||
| 18 | let p = embassy_stm32::init(Default::default()); | 19 | let p = embassy_stm32::init(Default::default()); |
| 19 | 20 | ||
| 20 | let config = Config::default(); | 21 | let config = Config::default(); |
| 21 | let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, p.DMA1_CH0, NoDma, config); | 22 | let irq = interrupt::take!(UART7); |
| 23 | let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, irq, p.DMA1_CH0, NoDma, config); | ||
| 22 | 24 | ||
| 23 | for n in 0u32.. { | 25 | for n in 0u32.. { |
| 24 | let mut s: String<128> = String::new(); | 26 | let mut s: String<128> = String::new(); |
diff --git a/examples/stm32h7/src/bin/usart_split.rs b/examples/stm32h7/src/bin/usart_split.rs index df2b600f8..f97176ecb 100644 --- a/examples/stm32h7/src/bin/usart_split.rs +++ b/examples/stm32h7/src/bin/usart_split.rs | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | use defmt::*; | 5 | use defmt::*; |
| 6 | use embassy_executor::Spawner; | 6 | use embassy_executor::Spawner; |
| 7 | use embassy_stm32::dma::NoDma; | 7 | use embassy_stm32::dma::NoDma; |
| 8 | use embassy_stm32::interrupt; | ||
| 8 | use embassy_stm32::peripherals::{DMA1_CH1, UART7}; | 9 | use embassy_stm32::peripherals::{DMA1_CH1, UART7}; |
| 9 | use embassy_stm32::usart::{Config, Uart, UartRx}; | 10 | use embassy_stm32::usart::{Config, Uart, UartRx}; |
| 10 | use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; | 11 | use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; |
| @@ -31,7 +32,8 @@ async fn main(spawner: Spawner) -> ! { | |||
| 31 | info!("Hello World!"); | 32 | info!("Hello World!"); |
| 32 | 33 | ||
| 33 | let config = Config::default(); | 34 | let config = Config::default(); |
| 34 | let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, p.DMA1_CH0, p.DMA1_CH1, config); | 35 | let irq = interrupt::take!(UART7); |
| 36 | let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, irq, p.DMA1_CH0, p.DMA1_CH1, config); | ||
| 35 | unwrap!(usart.blocking_write(b"Type 8 chars to echo!\r\n")); | 37 | unwrap!(usart.blocking_write(b"Type 8 chars to echo!\r\n")); |
| 36 | 38 | ||
| 37 | let (mut tx, rx) = usart.split(); | 39 | let (mut tx, rx) = usart.split(); |
diff --git a/examples/stm32l0/src/bin/usart_dma.rs b/examples/stm32l0/src/bin/usart_dma.rs index 66657d0f0..c307f857a 100644 --- a/examples/stm32l0/src/bin/usart_dma.rs +++ b/examples/stm32l0/src/bin/usart_dma.rs | |||
| @@ -4,13 +4,15 @@ | |||
| 4 | 4 | ||
| 5 | use defmt::*; | 5 | use defmt::*; |
| 6 | use embassy_executor::Spawner; | 6 | use embassy_executor::Spawner; |
| 7 | use embassy_stm32::interrupt; | ||
| 7 | use embassy_stm32::usart::{Config, Uart}; | 8 | use embassy_stm32::usart::{Config, Uart}; |
| 8 | use {defmt_rtt as _, panic_probe as _}; | 9 | use {defmt_rtt as _, panic_probe as _}; |
| 9 | 10 | ||
| 10 | #[embassy_executor::main] | 11 | #[embassy_executor::main] |
| 11 | async fn main(_spawner: Spawner) { | 12 | async fn main(_spawner: Spawner) { |
| 12 | let p = embassy_stm32::init(Default::default()); | 13 | let p = embassy_stm32::init(Default::default()); |
| 13 | let mut usart = Uart::new(p.USART1, p.PB7, p.PB6, p.DMA1_CH2, p.DMA1_CH3, Config::default()); | 14 | let irq = interrupt::take!(USART1); |
| 15 | let mut usart = Uart::new(p.USART1, p.PB7, p.PB6, irq, p.DMA1_CH2, p.DMA1_CH3, Config::default()); | ||
| 14 | 16 | ||
| 15 | usart.write(b"Hello Embassy World!\r\n").await.unwrap(); | 17 | usart.write(b"Hello Embassy World!\r\n").await.unwrap(); |
| 16 | info!("wrote Hello, starting echo"); | 18 | info!("wrote Hello, starting echo"); |
diff --git a/examples/stm32l0/src/bin/usart_irq.rs b/examples/stm32l0/src/bin/usart_irq.rs index 0e2237388..8e84cd092 100644 --- a/examples/stm32l0/src/bin/usart_irq.rs +++ b/examples/stm32l0/src/bin/usart_irq.rs | |||
| @@ -4,9 +4,8 @@ | |||
| 4 | 4 | ||
| 5 | use defmt::*; | 5 | use defmt::*; |
| 6 | use embassy_executor::Spawner; | 6 | use embassy_executor::Spawner; |
| 7 | use embassy_stm32::dma::NoDma; | ||
| 8 | use embassy_stm32::interrupt; | 7 | use embassy_stm32::interrupt; |
| 9 | use embassy_stm32::usart::{BufferedUart, Config, State, Uart}; | 8 | use embassy_stm32::usart::{BufferedUart, Config, State}; |
| 10 | use embedded_io::asynch::{Read, Write}; | 9 | use embedded_io::asynch::{Read, Write}; |
| 11 | use {defmt_rtt as _, panic_probe as _}; | 10 | use {defmt_rtt as _, panic_probe as _}; |
| 12 | 11 | ||
| @@ -21,15 +20,18 @@ async fn main(_spawner: Spawner) { | |||
| 21 | let mut config = Config::default(); | 20 | let mut config = Config::default(); |
| 22 | config.baudrate = 9600; | 21 | config.baudrate = 9600; |
| 23 | 22 | ||
| 24 | let usart = Uart::new(p.USART2, p.PA3, p.PA2, NoDma, NoDma, config); | ||
| 25 | let mut state = State::new(); | 23 | let mut state = State::new(); |
| 24 | let irq = interrupt::take!(USART2); | ||
| 26 | let mut usart = unsafe { | 25 | let mut usart = unsafe { |
| 27 | BufferedUart::new( | 26 | BufferedUart::new( |
| 28 | &mut state, | 27 | &mut state, |
| 29 | usart, | 28 | p.USART2, |
| 30 | interrupt::take!(USART2), | 29 | p.PA3, |
| 30 | p.PA2, | ||
| 31 | irq, | ||
| 31 | &mut TX_BUFFER, | 32 | &mut TX_BUFFER, |
| 32 | &mut RX_BUFFER, | 33 | &mut RX_BUFFER, |
| 34 | config, | ||
| 33 | ) | 35 | ) |
| 34 | }; | 36 | }; |
| 35 | 37 | ||
diff --git a/examples/stm32l4/src/bin/usart.rs b/examples/stm32l4/src/bin/usart.rs index 4a4b46c53..7d874d9d7 100644 --- a/examples/stm32l4/src/bin/usart.rs +++ b/examples/stm32l4/src/bin/usart.rs | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | 4 | ||
| 5 | use defmt::*; | 5 | use defmt::*; |
| 6 | use embassy_stm32::dma::NoDma; | 6 | use embassy_stm32::dma::NoDma; |
| 7 | use embassy_stm32::interrupt; | ||
| 7 | use embassy_stm32::usart::{Config, Uart}; | 8 | use embassy_stm32::usart::{Config, Uart}; |
| 8 | use {defmt_rtt as _, panic_probe as _}; | 9 | use {defmt_rtt as _, panic_probe as _}; |
| 9 | 10 | ||
| @@ -14,7 +15,8 @@ fn main() -> ! { | |||
| 14 | let p = embassy_stm32::init(Default::default()); | 15 | let p = embassy_stm32::init(Default::default()); |
| 15 | 16 | ||
| 16 | let config = Config::default(); | 17 | let config = Config::default(); |
| 17 | let mut usart = Uart::new(p.UART4, p.PA1, p.PA0, NoDma, NoDma, config); | 18 | let irq = interrupt::take!(UART4); |
| 19 | let mut usart = Uart::new(p.UART4, p.PA1, p.PA0, irq, NoDma, NoDma, config); | ||
| 18 | 20 | ||
| 19 | unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n")); | 21 | unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n")); |
| 20 | info!("wrote Hello, starting echo"); | 22 | info!("wrote Hello, starting echo"); |
diff --git a/examples/stm32l4/src/bin/usart_dma.rs b/examples/stm32l4/src/bin/usart_dma.rs index 728906897..452bede30 100644 --- a/examples/stm32l4/src/bin/usart_dma.rs +++ b/examples/stm32l4/src/bin/usart_dma.rs | |||
| @@ -7,6 +7,7 @@ use core::fmt::Write; | |||
| 7 | use defmt::*; | 7 | use defmt::*; |
| 8 | use embassy_executor::Spawner; | 8 | use embassy_executor::Spawner; |
| 9 | use embassy_stm32::dma::NoDma; | 9 | use embassy_stm32::dma::NoDma; |
| 10 | use embassy_stm32::interrupt; | ||
| 10 | use embassy_stm32::usart::{Config, Uart}; | 11 | use embassy_stm32::usart::{Config, Uart}; |
| 11 | use heapless::String; | 12 | use heapless::String; |
| 12 | use {defmt_rtt as _, panic_probe as _}; | 13 | use {defmt_rtt as _, panic_probe as _}; |
| @@ -17,7 +18,8 @@ async fn main(_spawner: Spawner) { | |||
| 17 | info!("Hello World!"); | 18 | info!("Hello World!"); |
| 18 | 19 | ||
| 19 | let config = Config::default(); | 20 | let config = Config::default(); |
| 20 | let mut usart = Uart::new(p.UART4, p.PA1, p.PA0, p.DMA1_CH3, NoDma, config); | 21 | let irq = interrupt::take!(UART4); |
| 22 | let mut usart = Uart::new(p.UART4, p.PA1, p.PA0, irq, p.DMA1_CH3, NoDma, config); | ||
| 21 | 23 | ||
| 22 | for n in 0u32.. { | 24 | for n in 0u32.. { |
| 23 | let mut s: String<128> = String::new(); | 25 | let mut s: String<128> = String::new(); |
diff --git a/tests/stm32/src/bin/usart.rs b/tests/stm32/src/bin/usart.rs index 7673bfe6d..af55867f2 100644 --- a/tests/stm32/src/bin/usart.rs +++ b/tests/stm32/src/bin/usart.rs | |||
| @@ -7,6 +7,7 @@ mod example_common; | |||
| 7 | use defmt::assert_eq; | 7 | use defmt::assert_eq; |
| 8 | use embassy_executor::Spawner; | 8 | use embassy_executor::Spawner; |
| 9 | use embassy_stm32::dma::NoDma; | 9 | use embassy_stm32::dma::NoDma; |
| 10 | use embassy_stm32::interrupt; | ||
| 10 | use embassy_stm32::usart::{Config, Uart}; | 11 | use embassy_stm32::usart::{Config, Uart}; |
| 11 | use example_common::*; | 12 | use example_common::*; |
| 12 | 13 | ||
| @@ -18,22 +19,22 @@ async fn main(_spawner: Spawner) { | |||
| 18 | // Arduino pins D0 and D1 | 19 | // Arduino pins D0 and D1 |
| 19 | // They're connected together with a 1K resistor. | 20 | // They're connected together with a 1K resistor. |
| 20 | #[cfg(feature = "stm32f103c8")] | 21 | #[cfg(feature = "stm32f103c8")] |
| 21 | let (tx, rx, usart) = (p.PA9, p.PA10, p.USART1); | 22 | let (tx, rx, usart, irq) = (p.PA9, p.PA10, p.USART1, interrupt::take!(USART1)); |
| 22 | #[cfg(feature = "stm32g491re")] | 23 | #[cfg(feature = "stm32g491re")] |
| 23 | let (tx, rx, usart) = (p.PC4, p.PC5, p.USART1); | 24 | let (tx, rx, usart, irq) = (p.PC4, p.PC5, p.USART1, interrupt::take!(USART1)); |
| 24 | #[cfg(feature = "stm32g071rb")] | 25 | #[cfg(feature = "stm32g071rb")] |
| 25 | let (tx, rx, usart) = (p.PC4, p.PC5, p.USART1); | 26 | let (tx, rx, usart, irq) = (p.PC4, p.PC5, p.USART1, interrupt::take!(USART1)); |
| 26 | #[cfg(feature = "stm32f429zi")] | 27 | #[cfg(feature = "stm32f429zi")] |
| 27 | let (tx, rx, usart) = (p.PG14, p.PG9, p.USART6); | 28 | let (tx, rx, usart, irq) = (p.PG14, p.PG9, p.USART6, interrupt::take!(USART6)); |
| 28 | #[cfg(feature = "stm32wb55rg")] | 29 | #[cfg(feature = "stm32wb55rg")] |
| 29 | let (tx, rx, usart) = (p.PA2, p.PA3, p.LPUART1); | 30 | let (tx, rx, usart, irq) = (p.PA2, p.PA3, p.LPUART1, interrupt::take!(LPUART1)); |
| 30 | #[cfg(feature = "stm32h755zi")] | 31 | #[cfg(feature = "stm32h755zi")] |
| 31 | let (tx, rx, usart) = (p.PB6, p.PB7, p.USART1); | 32 | let (tx, rx, usart, irq) = (p.PB6, p.PB7, p.USART1, interrupt::take!(USART1)); |
| 32 | #[cfg(feature = "stm32u585ai")] | 33 | #[cfg(feature = "stm32u585ai")] |
| 33 | let (tx, rx, usart) = (p.PD8, p.PD9, p.USART3); | 34 | let (tx, rx, usart, irq) = (p.PD8, p.PD9, p.USART3, interrupt::take!(USART3)); |
| 34 | 35 | ||
| 35 | let config = Config::default(); | 36 | let config = Config::default(); |
| 36 | let mut usart = Uart::new(usart, rx, tx, NoDma, NoDma, config); | 37 | let mut usart = Uart::new(usart, rx, tx, irq, NoDma, NoDma, config); |
| 37 | 38 | ||
| 38 | // We can't send too many bytes, they have to fit in the FIFO. | 39 | // We can't send too many bytes, they have to fit in the FIFO. |
| 39 | // This is because we aren't sending+receiving at the same time. | 40 | // This is because we aren't sending+receiving at the same time. |
diff --git a/tests/stm32/src/bin/usart_dma.rs b/tests/stm32/src/bin/usart_dma.rs index e0389446f..d12605a9a 100644 --- a/tests/stm32/src/bin/usart_dma.rs +++ b/tests/stm32/src/bin/usart_dma.rs | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | mod example_common; | 6 | mod example_common; |
| 7 | use defmt::assert_eq; | 7 | use defmt::assert_eq; |
| 8 | use embassy_executor::Spawner; | 8 | use embassy_executor::Spawner; |
| 9 | use embassy_stm32::interrupt; | ||
| 9 | use embassy_stm32::usart::{Config, Uart}; | 10 | use embassy_stm32::usart::{Config, Uart}; |
| 10 | use example_common::*; | 11 | use example_common::*; |
| 11 | 12 | ||
| @@ -17,22 +18,53 @@ async fn main(_spawner: Spawner) { | |||
| 17 | // Arduino pins D0 and D1 | 18 | // Arduino pins D0 and D1 |
| 18 | // They're connected together with a 1K resistor. | 19 | // They're connected together with a 1K resistor. |
| 19 | #[cfg(feature = "stm32f103c8")] | 20 | #[cfg(feature = "stm32f103c8")] |
| 20 | let (tx, rx, usart, tx_dma, rx_dma) = (p.PA9, p.PA10, p.USART1, p.DMA1_CH4, p.DMA1_CH5); | 21 | let (tx, rx, usart, irq, tx_dma, rx_dma) = ( |
| 22 | p.PA9, | ||
| 23 | p.PA10, | ||
| 24 | p.USART1, | ||
| 25 | interrupt::take!(USART1), | ||
| 26 | p.DMA1_CH4, | ||
| 27 | p.DMA1_CH5, | ||
| 28 | ); | ||
| 21 | #[cfg(feature = "stm32g491re")] | 29 | #[cfg(feature = "stm32g491re")] |
| 22 | let (tx, rx, usart, tx_dma, rx_dma) = (p.PC4, p.PC5, p.USART1, p.DMA1_CH1, p.DMA1_CH2); | 30 | let (tx, rx, usart, irq, tx_dma, rx_dma) = |
| 31 | (p.PC4, p.PC5, p.USART1, interrupt::take!(USART1), p.DMA1_CH1, p.DMA1_CH2); | ||
| 23 | #[cfg(feature = "stm32g071rb")] | 32 | #[cfg(feature = "stm32g071rb")] |
| 24 | let (tx, rx, usart, tx_dma, rx_dma) = (p.PC4, p.PC5, p.USART1, p.DMA1_CH1, p.DMA1_CH2); | 33 | let (tx, rx, usart, irq, tx_dma, rx_dma) = |
| 34 | (p.PC4, p.PC5, p.USART1, interrupt::take!(USART1), p.DMA1_CH1, p.DMA1_CH2); | ||
| 25 | #[cfg(feature = "stm32f429zi")] | 35 | #[cfg(feature = "stm32f429zi")] |
| 26 | let (tx, rx, usart, tx_dma, rx_dma) = (p.PG14, p.PG9, p.USART6, p.DMA2_CH6, p.DMA2_CH1); | 36 | let (tx, rx, usart, irq, tx_dma, rx_dma) = ( |
| 37 | p.PG14, | ||
| 38 | p.PG9, | ||
| 39 | p.USART6, | ||
| 40 | interrupt::take!(USART6), | ||
| 41 | p.DMA2_CH6, | ||
| 42 | p.DMA2_CH1, | ||
| 43 | ); | ||
| 27 | #[cfg(feature = "stm32wb55rg")] | 44 | #[cfg(feature = "stm32wb55rg")] |
| 28 | let (tx, rx, usart, tx_dma, rx_dma) = (p.PA2, p.PA3, p.LPUART1, p.DMA1_CH1, p.DMA1_CH2); | 45 | let (tx, rx, usart, irq, tx_dma, rx_dma) = ( |
| 46 | p.PA2, | ||
| 47 | p.PA3, | ||
| 48 | p.LPUART1, | ||
| 49 | interrupt::take!(LPUART1), | ||
| 50 | p.DMA1_CH1, | ||
| 51 | p.DMA1_CH2, | ||
| 52 | ); | ||
| 29 | #[cfg(feature = "stm32h755zi")] | 53 | #[cfg(feature = "stm32h755zi")] |
| 30 | let (tx, rx, usart, tx_dma, rx_dma) = (p.PB6, p.PB7, p.USART1, p.DMA1_CH0, p.DMA1_CH1); | 54 | let (tx, rx, usart, irq, tx_dma, rx_dma) = |
| 55 | (p.PB6, p.PB7, p.USART1, interrupt::take!(USART1), p.DMA1_CH0, p.DMA1_CH1); | ||
| 31 | #[cfg(feature = "stm32u585ai")] | 56 | #[cfg(feature = "stm32u585ai")] |
| 32 | let (tx, rx, usart, tx_dma, rx_dma) = (p.PD8, p.PD9, p.USART3, p.GPDMA1_CH0, p.GPDMA1_CH1); | 57 | let (tx, rx, usart, irq, tx_dma, rx_dma) = ( |
| 58 | p.PD8, | ||
| 59 | p.PD9, | ||
| 60 | p.USART3, | ||
| 61 | interrupt::take!(USART3), | ||
| 62 | p.GPDMA1_CH0, | ||
| 63 | p.GPDMA1_CH1, | ||
| 64 | ); | ||
| 33 | 65 | ||
| 34 | let config = Config::default(); | 66 | let config = Config::default(); |
| 35 | let mut usart = Uart::new(usart, rx, tx, tx_dma, rx_dma, config); | 67 | let mut usart = Uart::new(usart, rx, tx, irq, tx_dma, rx_dma, config); |
| 36 | 68 | ||
| 37 | // We can't send too many bytes, they have to fit in the FIFO. | 69 | // We can't send too many bytes, they have to fit in the FIFO. |
| 38 | // This is because we aren't sending+receiving at the same time. | 70 | // This is because we aren't sending+receiving at the same time. |
