diff options
| -rw-r--r-- | embassy-stm32/src/usart/mod.rs | 424 | ||||
| -rw-r--r-- | embassy-stm32/src/usart/v1.rs | 176 | ||||
| -rw-r--r-- | embassy-stm32/src/usart/v2.rs | 388 | ||||
| m--------- | stm32-data | 0 |
4 files changed, 418 insertions, 570 deletions
diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index 7cab10d05..a835093c5 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs | |||
| @@ -1,14 +1,18 @@ | |||
| 1 | #![macro_use] | 1 | #![macro_use] |
| 2 | 2 | ||
| 3 | #[cfg_attr(usart_v1, path = "v1.rs")] | 3 | use core::future::Future; |
| 4 | #[cfg_attr(usart_v2, path = "v2.rs")] | 4 | use core::marker::PhantomData; |
| 5 | mod _version; | 5 | use embassy::interrupt::Interrupt; |
| 6 | use crate::{dma, peripherals}; | 6 | use embassy::util::Unborrow; |
| 7 | pub use _version::*; | 7 | use embassy_hal_common::unborrow; |
| 8 | use futures::TryFutureExt; | ||
| 8 | 9 | ||
| 10 | use crate::dma::NoDma; | ||
| 11 | use crate::gpio::sealed::AFType::{OutputOpenDrain, OutputPushPull}; | ||
| 9 | use crate::gpio::Pin; | 12 | use crate::gpio::Pin; |
| 13 | use crate::pac::usart::{regs, vals}; | ||
| 10 | use crate::rcc::RccPeripheral; | 14 | use crate::rcc::RccPeripheral; |
| 11 | use embassy::interrupt::Interrupt; | 15 | use crate::{dma, peripherals}; |
| 12 | 16 | ||
| 13 | #[derive(Clone, Copy, PartialEq, Eq, Debug)] | 17 | #[derive(Clone, Copy, PartialEq, Eq, Debug)] |
| 14 | pub enum DataBits { | 18 | pub enum DataBits { |
| @@ -70,6 +74,414 @@ pub enum Error { | |||
| 70 | Parity, | 74 | Parity, |
| 71 | } | 75 | } |
| 72 | 76 | ||
| 77 | pub struct Uart<'d, T: Instance, TxDma = NoDma, RxDma = NoDma> { | ||
| 78 | inner: T, | ||
| 79 | phantom: PhantomData<&'d mut T>, | ||
| 80 | tx_dma: TxDma, | ||
| 81 | rx_dma: RxDma, | ||
| 82 | } | ||
| 83 | |||
| 84 | impl<'d, T: Instance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { | ||
| 85 | pub fn new( | ||
| 86 | inner: impl Unborrow<Target = T>, | ||
| 87 | rx: impl Unborrow<Target = impl RxPin<T>>, | ||
| 88 | tx: impl Unborrow<Target = impl TxPin<T>>, | ||
| 89 | tx_dma: impl Unborrow<Target = TxDma>, | ||
| 90 | rx_dma: impl Unborrow<Target = RxDma>, | ||
| 91 | config: Config, | ||
| 92 | ) -> Self { | ||
| 93 | unborrow!(inner, rx, tx, tx_dma, rx_dma); | ||
| 94 | |||
| 95 | T::enable(); | ||
| 96 | let pclk_freq = T::frequency(); | ||
| 97 | |||
| 98 | // TODO: better calculation, including error checking and OVER8 if possible. | ||
| 99 | let div = (pclk_freq.0 + (config.baudrate / 2)) / config.baudrate; | ||
| 100 | |||
| 101 | let r = inner.regs(); | ||
| 102 | |||
| 103 | unsafe { | ||
| 104 | rx.set_as_af(rx.af_num(), OutputOpenDrain); | ||
| 105 | tx.set_as_af(tx.af_num(), OutputPushPull); | ||
| 106 | |||
| 107 | r.cr2().write(|_w| {}); | ||
| 108 | r.cr3().write(|_w| {}); | ||
| 109 | r.brr().write_value(regs::Brr(div)); | ||
| 110 | r.cr1().write(|w| { | ||
| 111 | w.set_ue(true); | ||
| 112 | w.set_te(true); | ||
| 113 | w.set_re(true); | ||
| 114 | w.set_m0(vals::M0::BIT8); | ||
| 115 | w.set_pce(config.parity != Parity::ParityNone); | ||
| 116 | w.set_ps(match config.parity { | ||
| 117 | Parity::ParityOdd => vals::Ps::ODD, | ||
| 118 | Parity::ParityEven => vals::Ps::EVEN, | ||
| 119 | _ => vals::Ps::EVEN, | ||
| 120 | }); | ||
| 121 | }); | ||
| 122 | } | ||
| 123 | |||
| 124 | Self { | ||
| 125 | inner, | ||
| 126 | phantom: PhantomData, | ||
| 127 | tx_dma, | ||
| 128 | rx_dma, | ||
| 129 | } | ||
| 130 | } | ||
| 131 | |||
| 132 | async fn write_dma(&mut self, buffer: &[u8]) -> Result<(), Error> | ||
| 133 | where | ||
| 134 | TxDma: crate::usart::TxDma<T>, | ||
| 135 | { | ||
| 136 | let ch = &mut self.tx_dma; | ||
| 137 | let request = ch.request(); | ||
| 138 | unsafe { | ||
| 139 | self.inner.regs().cr3().modify(|reg| { | ||
| 140 | reg.set_dmat(true); | ||
| 141 | }); | ||
| 142 | } | ||
| 143 | let r = self.inner.regs(); | ||
| 144 | let dst = tdr(r); | ||
| 145 | crate::dma::write(ch, request, buffer, dst).await; | ||
| 146 | Ok(()) | ||
| 147 | } | ||
| 148 | |||
| 149 | async fn read_dma(&mut self, buffer: &mut [u8]) -> Result<(), Error> | ||
| 150 | where | ||
| 151 | RxDma: crate::usart::RxDma<T>, | ||
| 152 | { | ||
| 153 | let ch = &mut self.rx_dma; | ||
| 154 | let request = ch.request(); | ||
| 155 | unsafe { | ||
| 156 | self.inner.regs().cr3().modify(|reg| { | ||
| 157 | reg.set_dmar(true); | ||
| 158 | }); | ||
| 159 | } | ||
| 160 | let r = self.inner.regs(); | ||
| 161 | let src = rdr(r); | ||
| 162 | crate::dma::read(ch, request, src, buffer).await; | ||
| 163 | Ok(()) | ||
| 164 | } | ||
| 165 | |||
| 166 | pub fn read_blocking(&mut self, buffer: &mut [u8]) -> Result<(), Error> { | ||
| 167 | unsafe { | ||
| 168 | let r = self.inner.regs(); | ||
| 169 | for b in buffer { | ||
| 170 | loop { | ||
| 171 | let sr = sr(r).read(); | ||
| 172 | if sr.pe() { | ||
| 173 | rdr(r).read_volatile(); | ||
| 174 | return Err(Error::Parity); | ||
| 175 | } else if sr.fe() { | ||
| 176 | rdr(r).read_volatile(); | ||
| 177 | return Err(Error::Framing); | ||
| 178 | } else if sr.ne() { | ||
| 179 | rdr(r).read_volatile(); | ||
| 180 | return Err(Error::Noise); | ||
| 181 | } else if sr.ore() { | ||
| 182 | rdr(r).read_volatile(); | ||
| 183 | return Err(Error::Overrun); | ||
| 184 | } else if sr.rxne() { | ||
| 185 | break; | ||
| 186 | } | ||
| 187 | } | ||
| 188 | *b = rdr(r).read_volatile(); | ||
| 189 | } | ||
| 190 | } | ||
| 191 | Ok(()) | ||
| 192 | } | ||
| 193 | } | ||
| 194 | |||
| 195 | impl<'d, T: Instance, RxDma> embedded_hal::blocking::serial::Write<u8> | ||
| 196 | for Uart<'d, T, NoDma, RxDma> | ||
| 197 | { | ||
| 198 | type Error = Error; | ||
| 199 | fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> { | ||
| 200 | unsafe { | ||
| 201 | let r = self.inner.regs(); | ||
| 202 | for &b in buffer { | ||
| 203 | while !sr(r).read().txe() {} | ||
| 204 | tdr(r).write_volatile(b); | ||
| 205 | } | ||
| 206 | } | ||
| 207 | Ok(()) | ||
| 208 | } | ||
| 209 | fn bflush(&mut self) -> Result<(), Self::Error> { | ||
| 210 | unsafe { | ||
| 211 | let r = self.inner.regs(); | ||
| 212 | while !sr(r).read().tc() {} | ||
| 213 | } | ||
| 214 | Ok(()) | ||
| 215 | } | ||
| 216 | } | ||
| 217 | |||
| 218 | impl<'d, T: Instance, TxDma, RxDma> embassy_traits::uart::Write for Uart<'d, T, TxDma, RxDma> | ||
| 219 | where | ||
| 220 | TxDma: crate::usart::TxDma<T>, | ||
| 221 | { | ||
| 222 | #[rustfmt::skip] | ||
| 223 | type WriteFuture<'a> where Self: 'a = impl Future<Output = Result<(), embassy_traits::uart::Error>> + 'a; | ||
| 224 | |||
| 225 | fn write<'a>(&'a mut self, buf: &'a [u8]) -> Self::WriteFuture<'a> { | ||
| 226 | self.write_dma(buf) | ||
| 227 | .map_err(|_| embassy_traits::uart::Error::Other) | ||
| 228 | } | ||
| 229 | } | ||
| 230 | |||
| 231 | impl<'d, T: Instance, TxDma, RxDma> embassy_traits::uart::Read for Uart<'d, T, TxDma, RxDma> | ||
| 232 | where | ||
| 233 | RxDma: crate::usart::RxDma<T>, | ||
| 234 | { | ||
| 235 | #[rustfmt::skip] | ||
| 236 | type ReadFuture<'a> where Self: 'a = impl Future<Output = Result<(), embassy_traits::uart::Error>> + 'a; | ||
| 237 | |||
| 238 | fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReadFuture<'a> { | ||
| 239 | self.read_dma(buf) | ||
| 240 | .map_err(|_| embassy_traits::uart::Error::Other) | ||
| 241 | } | ||
| 242 | } | ||
| 243 | |||
| 244 | #[cfg(usart_v2)] | ||
| 245 | pub use buffered::*; | ||
| 246 | #[cfg(usart_v2)] | ||
| 247 | mod buffered { | ||
| 248 | use atomic_polyfill::{compiler_fence, Ordering}; | ||
| 249 | use core::pin::Pin; | ||
| 250 | use core::task::Context; | ||
| 251 | use core::task::Poll; | ||
| 252 | use embassy::waitqueue::WakerRegistration; | ||
| 253 | use embassy_hal_common::peripheral::{PeripheralMutex, PeripheralState, StateStorage}; | ||
| 254 | use embassy_hal_common::ring_buffer::RingBuffer; | ||
| 255 | |||
| 256 | use super::*; | ||
| 257 | |||
| 258 | pub struct State<'d, T: Instance>(StateStorage<StateInner<'d, T>>); | ||
| 259 | impl<'d, T: Instance> State<'d, T> { | ||
| 260 | pub fn new() -> Self { | ||
| 261 | Self(StateStorage::new()) | ||
| 262 | } | ||
| 263 | } | ||
| 264 | |||
| 265 | struct StateInner<'d, T: Instance> { | ||
| 266 | uart: Uart<'d, T, NoDma, NoDma>, | ||
| 267 | phantom: PhantomData<&'d mut T>, | ||
| 268 | |||
| 269 | rx_waker: WakerRegistration, | ||
| 270 | rx: RingBuffer<'d>, | ||
| 271 | |||
| 272 | tx_waker: WakerRegistration, | ||
| 273 | tx: RingBuffer<'d>, | ||
| 274 | } | ||
| 275 | |||
| 276 | unsafe impl<'d, T: Instance> Send for StateInner<'d, T> {} | ||
| 277 | unsafe impl<'d, T: Instance> Sync for StateInner<'d, T> {} | ||
| 278 | |||
| 279 | pub struct BufferedUart<'d, T: Instance> { | ||
| 280 | inner: PeripheralMutex<'d, StateInner<'d, T>>, | ||
| 281 | } | ||
| 282 | |||
| 283 | impl<'d, T: Instance> Unpin for BufferedUart<'d, T> {} | ||
| 284 | |||
| 285 | impl<'d, T: Instance> BufferedUart<'d, T> { | ||
| 286 | pub unsafe fn new( | ||
| 287 | state: &'d mut State<'d, T>, | ||
| 288 | uart: Uart<'d, T, NoDma, NoDma>, | ||
| 289 | irq: impl Unborrow<Target = T::Interrupt> + 'd, | ||
| 290 | tx_buffer: &'d mut [u8], | ||
| 291 | rx_buffer: &'d mut [u8], | ||
| 292 | ) -> BufferedUart<'d, T> { | ||
| 293 | unborrow!(irq); | ||
| 294 | |||
| 295 | let r = uart.inner.regs(); | ||
| 296 | r.cr1().modify(|w| { | ||
| 297 | w.set_rxneie(true); | ||
| 298 | w.set_idleie(true); | ||
| 299 | }); | ||
| 300 | |||
| 301 | Self { | ||
| 302 | inner: PeripheralMutex::new_unchecked(irq, &mut state.0, move || StateInner { | ||
| 303 | uart, | ||
| 304 | phantom: PhantomData, | ||
| 305 | tx: RingBuffer::new(tx_buffer), | ||
| 306 | tx_waker: WakerRegistration::new(), | ||
| 307 | |||
| 308 | rx: RingBuffer::new(rx_buffer), | ||
| 309 | rx_waker: WakerRegistration::new(), | ||
| 310 | }), | ||
| 311 | } | ||
| 312 | } | ||
| 313 | } | ||
| 314 | |||
| 315 | impl<'d, T: Instance> StateInner<'d, T> | ||
| 316 | where | ||
| 317 | Self: 'd, | ||
| 318 | { | ||
| 319 | fn on_rx(&mut self) { | ||
| 320 | let r = self.uart.inner.regs(); | ||
| 321 | unsafe { | ||
| 322 | let sr = r.isr().read(); | ||
| 323 | if sr.pe() { | ||
| 324 | r.icr().write(|w| { | ||
| 325 | w.set_pe(true); | ||
| 326 | }); | ||
| 327 | trace!("Parity error"); | ||
| 328 | } else if sr.fe() { | ||
| 329 | r.icr().write(|w| { | ||
| 330 | w.set_fe(true); | ||
| 331 | }); | ||
| 332 | trace!("Framing error"); | ||
| 333 | } else if sr.ne() { | ||
| 334 | r.icr().write(|w| { | ||
| 335 | w.set_ne(true); | ||
| 336 | }); | ||
| 337 | trace!("Noise error"); | ||
| 338 | } else if sr.ore() { | ||
| 339 | r.icr().write(|w| { | ||
| 340 | w.set_ore(true); | ||
| 341 | }); | ||
| 342 | trace!("Overrun error"); | ||
| 343 | } else if sr.rxne() { | ||
| 344 | let buf = self.rx.push_buf(); | ||
| 345 | if buf.is_empty() { | ||
| 346 | self.rx_waker.wake(); | ||
| 347 | } else { | ||
| 348 | buf[0] = r.rdr().read().0 as u8; | ||
| 349 | self.rx.push(1); | ||
| 350 | } | ||
| 351 | } else if sr.idle() { | ||
| 352 | r.icr().write(|w| { | ||
| 353 | w.set_idle(true); | ||
| 354 | }); | ||
| 355 | self.rx_waker.wake(); | ||
| 356 | }; | ||
| 357 | } | ||
| 358 | } | ||
| 359 | |||
| 360 | fn on_tx(&mut self) { | ||
| 361 | let r = self.uart.inner.regs(); | ||
| 362 | unsafe { | ||
| 363 | if r.isr().read().txe() { | ||
| 364 | let buf = self.tx.pop_buf(); | ||
| 365 | if !buf.is_empty() { | ||
| 366 | r.cr1().modify(|w| { | ||
| 367 | w.set_txeie(true); | ||
| 368 | }); | ||
| 369 | r.tdr().write_value(regs::Dr(buf[0].into())); | ||
| 370 | self.tx.pop(1); | ||
| 371 | self.tx_waker.wake(); | ||
| 372 | } else { | ||
| 373 | // Disable interrupt until we have something to transmit again | ||
| 374 | r.cr1().modify(|w| { | ||
| 375 | w.set_txeie(false); | ||
| 376 | }); | ||
| 377 | } | ||
| 378 | } | ||
| 379 | } | ||
| 380 | } | ||
| 381 | } | ||
| 382 | |||
| 383 | impl<'d, T: Instance> PeripheralState for StateInner<'d, T> | ||
| 384 | where | ||
| 385 | Self: 'd, | ||
| 386 | { | ||
| 387 | type Interrupt = T::Interrupt; | ||
| 388 | fn on_interrupt(&mut self) { | ||
| 389 | self.on_rx(); | ||
| 390 | self.on_tx(); | ||
| 391 | } | ||
| 392 | } | ||
| 393 | |||
| 394 | impl<'d, T: Instance> embassy::io::AsyncBufRead for BufferedUart<'d, T> { | ||
| 395 | fn poll_fill_buf( | ||
| 396 | mut self: Pin<&mut Self>, | ||
| 397 | cx: &mut Context<'_>, | ||
| 398 | ) -> Poll<Result<&[u8], embassy::io::Error>> { | ||
| 399 | self.inner.with(|state| { | ||
| 400 | compiler_fence(Ordering::SeqCst); | ||
| 401 | |||
| 402 | // We have data ready in buffer? Return it. | ||
| 403 | let buf = state.rx.pop_buf(); | ||
| 404 | if !buf.is_empty() { | ||
| 405 | let buf: &[u8] = buf; | ||
| 406 | // Safety: buffer lives as long as uart | ||
| 407 | let buf: &[u8] = unsafe { core::mem::transmute(buf) }; | ||
| 408 | return Poll::Ready(Ok(buf)); | ||
| 409 | } | ||
| 410 | |||
| 411 | state.rx_waker.register(cx.waker()); | ||
| 412 | Poll::<Result<&[u8], embassy::io::Error>>::Pending | ||
| 413 | }) | ||
| 414 | } | ||
| 415 | fn consume(mut self: Pin<&mut Self>, amt: usize) { | ||
| 416 | let signal = self.inner.with(|state| { | ||
| 417 | let full = state.rx.is_full(); | ||
| 418 | state.rx.pop(amt); | ||
| 419 | full | ||
| 420 | }); | ||
| 421 | if signal { | ||
| 422 | self.inner.pend(); | ||
| 423 | } | ||
| 424 | } | ||
| 425 | } | ||
| 426 | |||
| 427 | impl<'d, T: Instance> embassy::io::AsyncWrite for BufferedUart<'d, T> { | ||
| 428 | fn poll_write( | ||
| 429 | mut self: Pin<&mut Self>, | ||
| 430 | cx: &mut Context<'_>, | ||
| 431 | buf: &[u8], | ||
| 432 | ) -> Poll<Result<usize, embassy::io::Error>> { | ||
| 433 | let (poll, empty) = self.inner.with(|state| { | ||
| 434 | let empty = state.tx.is_empty(); | ||
| 435 | let tx_buf = state.tx.push_buf(); | ||
| 436 | if tx_buf.is_empty() { | ||
| 437 | state.tx_waker.register(cx.waker()); | ||
| 438 | return (Poll::Pending, empty); | ||
| 439 | } | ||
| 440 | |||
| 441 | let n = core::cmp::min(tx_buf.len(), buf.len()); | ||
| 442 | tx_buf[..n].copy_from_slice(&buf[..n]); | ||
| 443 | state.tx.push(n); | ||
| 444 | |||
| 445 | (Poll::Ready(Ok(n)), empty) | ||
| 446 | }); | ||
| 447 | if empty { | ||
| 448 | self.inner.pend(); | ||
| 449 | } | ||
| 450 | poll | ||
| 451 | } | ||
| 452 | } | ||
| 453 | } | ||
| 454 | |||
| 455 | #[cfg(usart_v1)] | ||
| 456 | fn tdr(r: crate::pac::usart::Usart) -> *mut u8 { | ||
| 457 | r.dr().ptr() as _ | ||
| 458 | } | ||
| 459 | |||
| 460 | #[cfg(usart_v1)] | ||
| 461 | fn rdr(r: crate::pac::usart::Usart) -> *mut u8 { | ||
| 462 | r.dr().ptr() as _ | ||
| 463 | } | ||
| 464 | |||
| 465 | #[cfg(usart_v1)] | ||
| 466 | fn sr(r: crate::pac::usart::Usart) -> crate::pac::common::Reg<regs::Sr, crate::pac::common::RW> { | ||
| 467 | r.sr() | ||
| 468 | } | ||
| 469 | |||
| 470 | #[cfg(usart_v2)] | ||
| 471 | fn tdr(r: crate::pac::usart::Usart) -> *mut u8 { | ||
| 472 | r.tdr().ptr() as _ | ||
| 473 | } | ||
| 474 | |||
| 475 | #[cfg(usart_v2)] | ||
| 476 | fn rdr(r: crate::pac::usart::Usart) -> *mut u8 { | ||
| 477 | r.rdr().ptr() as _ | ||
| 478 | } | ||
| 479 | |||
| 480 | #[cfg(usart_v2)] | ||
| 481 | fn sr(r: crate::pac::usart::Usart) -> crate::pac::common::Reg<regs::Ixr, crate::pac::common::R> { | ||
| 482 | r.isr() | ||
| 483 | } | ||
| 484 | |||
| 73 | pub(crate) mod sealed { | 485 | pub(crate) mod sealed { |
| 74 | use super::*; | 486 | use super::*; |
| 75 | 487 | ||
diff --git a/embassy-stm32/src/usart/v1.rs b/embassy-stm32/src/usart/v1.rs deleted file mode 100644 index 10f87f2dd..000000000 --- a/embassy-stm32/src/usart/v1.rs +++ /dev/null | |||
| @@ -1,176 +0,0 @@ | |||
| 1 | use crate::gpio::sealed::AFType::{OutputOpenDrain, OutputPushPull}; | ||
| 2 | use core::future::Future; | ||
| 3 | use core::marker::PhantomData; | ||
| 4 | use embassy::util::Unborrow; | ||
| 5 | use embassy_hal_common::unborrow; | ||
| 6 | use futures::TryFutureExt; | ||
| 7 | |||
| 8 | use super::*; | ||
| 9 | use crate::dma::NoDma; | ||
| 10 | use crate::pac::usart::{regs, vals}; | ||
| 11 | |||
| 12 | pub struct Uart<'d, T: Instance, TxDma = NoDma, RxDma = NoDma> { | ||
| 13 | inner: T, | ||
| 14 | phantom: PhantomData<&'d mut T>, | ||
| 15 | tx_dma: TxDma, | ||
| 16 | #[allow(dead_code)] | ||
| 17 | rx_dma: RxDma, | ||
| 18 | } | ||
| 19 | |||
| 20 | impl<'d, T: Instance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { | ||
| 21 | pub fn new( | ||
| 22 | inner: impl Unborrow<Target = T>, | ||
| 23 | rx: impl Unborrow<Target = impl RxPin<T>>, | ||
| 24 | tx: impl Unborrow<Target = impl TxPin<T>>, | ||
| 25 | tx_dma: impl Unborrow<Target = TxDma>, | ||
| 26 | rx_dma: impl Unborrow<Target = RxDma>, | ||
| 27 | config: Config, | ||
| 28 | ) -> Self { | ||
| 29 | unborrow!(inner, rx, tx, tx_dma, rx_dma); | ||
| 30 | |||
| 31 | T::enable(); | ||
| 32 | let pclk_freq = T::frequency(); | ||
| 33 | |||
| 34 | // TODO: better calculation, including error checking and OVER8 if possible. | ||
| 35 | let div = (pclk_freq.0 + (config.baudrate / 2)) / config.baudrate; | ||
| 36 | |||
| 37 | let r = inner.regs(); | ||
| 38 | |||
| 39 | unsafe { | ||
| 40 | rx.set_as_af(rx.af_num(), OutputOpenDrain); | ||
| 41 | tx.set_as_af(tx.af_num(), OutputPushPull); | ||
| 42 | |||
| 43 | r.brr().write_value(regs::Brr(div)); | ||
| 44 | r.cr1().write(|w| { | ||
| 45 | w.set_ue(true); | ||
| 46 | w.set_te(true); | ||
| 47 | w.set_re(true); | ||
| 48 | w.set_m(vals::M::M8); | ||
| 49 | w.set_pce(config.parity != Parity::ParityNone); | ||
| 50 | w.set_ps(match config.parity { | ||
| 51 | Parity::ParityOdd => vals::Ps::ODD, | ||
| 52 | Parity::ParityEven => vals::Ps::EVEN, | ||
| 53 | _ => vals::Ps::EVEN, | ||
| 54 | }); | ||
| 55 | }); | ||
| 56 | r.cr2().write(|_w| {}); | ||
| 57 | r.cr3().write(|_w| {}); | ||
| 58 | } | ||
| 59 | |||
| 60 | Self { | ||
| 61 | inner, | ||
| 62 | phantom: PhantomData, | ||
| 63 | tx_dma, | ||
| 64 | rx_dma, | ||
| 65 | } | ||
| 66 | } | ||
| 67 | |||
| 68 | async fn write_dma(&mut self, buffer: &[u8]) -> Result<(), Error> | ||
| 69 | where | ||
| 70 | TxDma: crate::usart::TxDma<T>, | ||
| 71 | { | ||
| 72 | let ch = &mut self.tx_dma; | ||
| 73 | let request = ch.request(); | ||
| 74 | unsafe { | ||
| 75 | self.inner.regs().cr3().modify(|reg| { | ||
| 76 | reg.set_dmat(true); | ||
| 77 | }); | ||
| 78 | } | ||
| 79 | let r = self.inner.regs(); | ||
| 80 | let dst = r.dr().ptr() as *mut u8; | ||
| 81 | crate::dma::write(ch, request, buffer, dst).await; | ||
| 82 | Ok(()) | ||
| 83 | } | ||
| 84 | |||
| 85 | async fn read_dma(&mut self, buffer: &mut [u8]) -> Result<(), Error> | ||
| 86 | where | ||
| 87 | RxDma: crate::usart::RxDma<T>, | ||
| 88 | { | ||
| 89 | let ch = &mut self.rx_dma; | ||
| 90 | let request = ch.request(); | ||
| 91 | unsafe { | ||
| 92 | self.inner.regs().cr3().modify(|reg| { | ||
| 93 | reg.set_dmar(true); | ||
| 94 | }); | ||
| 95 | } | ||
| 96 | let r = self.inner.regs(); | ||
| 97 | let src = r.dr().ptr() as *mut u8; | ||
| 98 | crate::dma::read(ch, request, src, buffer).await; | ||
| 99 | Ok(()) | ||
| 100 | } | ||
| 101 | |||
| 102 | pub fn read_blocking(&mut self, buffer: &mut [u8]) -> Result<(), Error> { | ||
| 103 | unsafe { | ||
| 104 | let r = self.inner.regs(); | ||
| 105 | for b in buffer { | ||
| 106 | loop { | ||
| 107 | let sr = r.sr().read(); | ||
| 108 | if sr.pe() { | ||
| 109 | r.dr().read(); | ||
| 110 | return Err(Error::Parity); | ||
| 111 | } else if sr.fe() { | ||
| 112 | r.dr().read(); | ||
| 113 | return Err(Error::Framing); | ||
| 114 | } else if sr.ne() { | ||
| 115 | r.dr().read(); | ||
| 116 | return Err(Error::Noise); | ||
| 117 | } else if sr.ore() { | ||
| 118 | r.dr().read(); | ||
| 119 | return Err(Error::Overrun); | ||
| 120 | } else if sr.rxne() { | ||
| 121 | break; | ||
| 122 | } | ||
| 123 | } | ||
| 124 | *b = r.dr().read().0 as u8; | ||
| 125 | } | ||
| 126 | } | ||
| 127 | Ok(()) | ||
| 128 | } | ||
| 129 | } | ||
| 130 | |||
| 131 | impl<'d, T: Instance, RxDma> embedded_hal::blocking::serial::Write<u8> | ||
| 132 | for Uart<'d, T, NoDma, RxDma> | ||
| 133 | { | ||
| 134 | type Error = Error; | ||
| 135 | fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> { | ||
| 136 | unsafe { | ||
| 137 | let r = self.inner.regs(); | ||
| 138 | for &b in buffer { | ||
| 139 | while !r.sr().read().txe() {} | ||
| 140 | r.dr().write_value(regs::Dr(b as u32)) | ||
| 141 | } | ||
| 142 | } | ||
| 143 | Ok(()) | ||
| 144 | } | ||
| 145 | fn bflush(&mut self) -> Result<(), Self::Error> { | ||
| 146 | unsafe { | ||
| 147 | let r = self.inner.regs(); | ||
| 148 | while !r.sr().read().tc() {} | ||
| 149 | } | ||
| 150 | Ok(()) | ||
| 151 | } | ||
| 152 | } | ||
| 153 | |||
| 154 | // rustfmt::skip because intellij removes the 'where' claus on the associated type. | ||
| 155 | #[rustfmt::skip] | ||
| 156 | impl<'d, T: Instance, TxDma, RxDma> embassy_traits::uart::Write for Uart<'d, T, TxDma, RxDma> | ||
| 157 | where TxDma: crate::usart::TxDma<T> | ||
| 158 | { | ||
| 159 | type WriteFuture<'a> where Self: 'a = impl Future<Output = Result<(), embassy_traits::uart::Error>> + 'a; | ||
| 160 | |||
| 161 | fn write<'a>(&'a mut self, buf: &'a [u8]) -> Self::WriteFuture<'a> { | ||
| 162 | self.write_dma(buf).map_err(|_| embassy_traits::uart::Error::Other) | ||
| 163 | } | ||
| 164 | } | ||
| 165 | |||
| 166 | // rustfmt::skip because intellij removes the 'where' claus on the associated type. | ||
| 167 | #[rustfmt::skip] | ||
| 168 | impl<'d, T: Instance, TxDma, RxDma> embassy_traits::uart::Read for Uart<'d, T, TxDma, RxDma> | ||
| 169 | where RxDma: crate::usart::RxDma<T> | ||
| 170 | { | ||
| 171 | type ReadFuture<'a> where Self: 'a = impl Future<Output = Result<(), embassy_traits::uart::Error>> + 'a; | ||
| 172 | |||
| 173 | fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReadFuture<'a> { | ||
| 174 | self.read_dma(buf).map_err(|_| embassy_traits::uart::Error::Other) | ||
| 175 | } | ||
| 176 | } | ||
diff --git a/embassy-stm32/src/usart/v2.rs b/embassy-stm32/src/usart/v2.rs deleted file mode 100644 index 697adf459..000000000 --- a/embassy-stm32/src/usart/v2.rs +++ /dev/null | |||
| @@ -1,388 +0,0 @@ | |||
| 1 | use atomic_polyfill::{compiler_fence, Ordering}; | ||
| 2 | use core::future::Future; | ||
| 3 | use core::marker::PhantomData; | ||
| 4 | use core::pin::Pin; | ||
| 5 | use core::task::Context; | ||
| 6 | use core::task::Poll; | ||
| 7 | use embassy::util::Unborrow; | ||
| 8 | use embassy::waitqueue::WakerRegistration; | ||
| 9 | use embassy_hal_common::peripheral::{PeripheralMutex, PeripheralState, StateStorage}; | ||
| 10 | use embassy_hal_common::ring_buffer::RingBuffer; | ||
| 11 | use embassy_hal_common::unborrow; | ||
| 12 | use futures::TryFutureExt; | ||
| 13 | |||
| 14 | use super::*; | ||
| 15 | use crate::dma::NoDma; | ||
| 16 | use crate::gpio::sealed::AFType::{OutputOpenDrain, OutputPushPull}; | ||
| 17 | use crate::pac::usart::{regs, vals}; | ||
| 18 | |||
| 19 | pub struct Uart<'d, T: Instance, TxDma = NoDma, RxDma = NoDma> { | ||
| 20 | inner: T, | ||
| 21 | phantom: PhantomData<&'d mut T>, | ||
| 22 | tx_dma: TxDma, | ||
| 23 | rx_dma: RxDma, | ||
| 24 | } | ||
| 25 | |||
| 26 | impl<'d, T: Instance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { | ||
| 27 | pub fn new( | ||
| 28 | inner: impl Unborrow<Target = T>, | ||
| 29 | rx: impl Unborrow<Target = impl RxPin<T>>, | ||
| 30 | tx: impl Unborrow<Target = impl TxPin<T>>, | ||
| 31 | tx_dma: impl Unborrow<Target = TxDma>, | ||
| 32 | rx_dma: impl Unborrow<Target = RxDma>, | ||
| 33 | config: Config, | ||
| 34 | ) -> Self { | ||
| 35 | unborrow!(inner, rx, tx, tx_dma, rx_dma); | ||
| 36 | |||
| 37 | T::enable(); | ||
| 38 | let pclk_freq = T::frequency(); | ||
| 39 | |||
| 40 | // TODO: better calculation, including error checking and OVER8 if possible. | ||
| 41 | let div = (pclk_freq.0 + (config.baudrate / 2)) / config.baudrate; | ||
| 42 | |||
| 43 | let r = inner.regs(); | ||
| 44 | |||
| 45 | unsafe { | ||
| 46 | rx.set_as_af(rx.af_num(), OutputOpenDrain); | ||
| 47 | tx.set_as_af(tx.af_num(), OutputPushPull); | ||
| 48 | |||
| 49 | r.cr2().write(|_w| {}); | ||
| 50 | r.cr3().write(|_w| {}); | ||
| 51 | |||
| 52 | r.brr().write(|w| w.set_brr(div as u16)); | ||
| 53 | r.cr1().write(|w| { | ||
| 54 | w.set_ue(true); | ||
| 55 | w.set_te(true); | ||
| 56 | w.set_re(true); | ||
| 57 | w.set_m0(vals::M0::BIT8); | ||
| 58 | w.set_m1(vals::M1::M0); | ||
| 59 | w.set_pce(config.parity != Parity::ParityNone); | ||
| 60 | w.set_ps(match config.parity { | ||
| 61 | Parity::ParityOdd => vals::Ps::ODD, | ||
| 62 | Parity::ParityEven => vals::Ps::EVEN, | ||
| 63 | _ => vals::Ps::EVEN, | ||
| 64 | }); | ||
| 65 | }); | ||
| 66 | r.cr2().write(|_w| {}); | ||
| 67 | r.cr3().write(|_w| {}); | ||
| 68 | } | ||
| 69 | |||
| 70 | Self { | ||
| 71 | inner, | ||
| 72 | phantom: PhantomData, | ||
| 73 | tx_dma, | ||
| 74 | rx_dma, | ||
| 75 | } | ||
| 76 | } | ||
| 77 | |||
| 78 | async fn write_dma(&mut self, buffer: &[u8]) -> Result<(), Error> | ||
| 79 | where | ||
| 80 | TxDma: crate::usart::TxDma<T>, | ||
| 81 | { | ||
| 82 | let ch = &mut self.tx_dma; | ||
| 83 | let request = ch.request(); | ||
| 84 | unsafe { | ||
| 85 | self.inner.regs().cr3().modify(|reg| { | ||
| 86 | reg.set_dmat(true); | ||
| 87 | }); | ||
| 88 | } | ||
| 89 | let r = self.inner.regs(); | ||
| 90 | let dst = r.tdr().ptr() as *mut u8; | ||
| 91 | crate::dma::write(ch, request, buffer, dst).await; | ||
| 92 | Ok(()) | ||
| 93 | } | ||
| 94 | |||
| 95 | async fn read_dma(&mut self, buffer: &mut [u8]) -> Result<(), Error> | ||
| 96 | where | ||
| 97 | RxDma: crate::usart::RxDma<T>, | ||
| 98 | { | ||
| 99 | let ch = &mut self.rx_dma; | ||
| 100 | let request = ch.request(); | ||
| 101 | unsafe { | ||
| 102 | self.inner.regs().cr3().modify(|reg| { | ||
| 103 | reg.set_dmar(true); | ||
| 104 | }); | ||
| 105 | } | ||
| 106 | let r = self.inner.regs(); | ||
| 107 | let src = r.rdr().ptr() as *mut u8; | ||
| 108 | |||
| 109 | crate::dma::read(ch, request, src, buffer).await; | ||
| 110 | Ok(()) | ||
| 111 | } | ||
| 112 | |||
| 113 | pub fn read_blocking(&mut self, buffer: &mut [u8]) -> Result<(), Error> { | ||
| 114 | unsafe { | ||
| 115 | let r = self.inner.regs(); | ||
| 116 | for b in buffer { | ||
| 117 | loop { | ||
| 118 | let sr = r.isr().read(); | ||
| 119 | if sr.pe() { | ||
| 120 | r.rdr().read(); | ||
| 121 | return Err(Error::Parity); | ||
| 122 | } else if sr.fe() { | ||
| 123 | r.rdr().read(); | ||
| 124 | return Err(Error::Framing); | ||
| 125 | } else if sr.nf() { | ||
| 126 | r.rdr().read(); | ||
| 127 | return Err(Error::Noise); | ||
| 128 | } else if sr.ore() { | ||
| 129 | r.rdr().read(); | ||
| 130 | return Err(Error::Overrun); | ||
| 131 | } else if sr.rxne() { | ||
| 132 | break; | ||
| 133 | } | ||
| 134 | } | ||
| 135 | *b = r.rdr().read().0 as u8; | ||
| 136 | } | ||
| 137 | } | ||
| 138 | Ok(()) | ||
| 139 | } | ||
| 140 | } | ||
| 141 | |||
| 142 | impl<'d, T: Instance, RxDma> embedded_hal::blocking::serial::Write<u8> | ||
| 143 | for Uart<'d, T, NoDma, RxDma> | ||
| 144 | { | ||
| 145 | type Error = Error; | ||
| 146 | fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> { | ||
| 147 | unsafe { | ||
| 148 | let r = self.inner.regs(); | ||
| 149 | for &b in buffer { | ||
| 150 | while !r.isr().read().txe() {} | ||
| 151 | r.tdr().write_value(regs::Dr(b as u32)) | ||
| 152 | } | ||
| 153 | } | ||
| 154 | Ok(()) | ||
| 155 | } | ||
| 156 | fn bflush(&mut self) -> Result<(), Self::Error> { | ||
| 157 | unsafe { | ||
| 158 | let r = self.inner.regs(); | ||
| 159 | while !r.isr().read().tc() {} | ||
| 160 | } | ||
| 161 | Ok(()) | ||
| 162 | } | ||
| 163 | } | ||
| 164 | |||
| 165 | // rustfmt::skip because intellij removes the 'where' claus on the associated type. | ||
| 166 | impl<'d, T: Instance, TxDma, RxDma> embassy_traits::uart::Write for Uart<'d, T, TxDma, RxDma> | ||
| 167 | where | ||
| 168 | TxDma: crate::usart::TxDma<T>, | ||
| 169 | { | ||
| 170 | // rustfmt::skip because rustfmt removes the 'where' claus on the associated type. | ||
| 171 | #[rustfmt::skip] | ||
| 172 | type WriteFuture<'a> where Self: 'a = impl Future<Output = Result<(), embassy_traits::uart::Error>> +'a; | ||
| 173 | |||
| 174 | fn write<'a>(&'a mut self, buf: &'a [u8]) -> Self::WriteFuture<'a> { | ||
| 175 | self.write_dma(buf) | ||
| 176 | .map_err(|_| embassy_traits::uart::Error::Other) | ||
| 177 | } | ||
| 178 | } | ||
| 179 | |||
| 180 | impl<'d, T: Instance, TxDma, RxDma> embassy_traits::uart::Read for Uart<'d, T, TxDma, RxDma> | ||
| 181 | where | ||
| 182 | RxDma: crate::usart::RxDma<T>, | ||
| 183 | { | ||
| 184 | // rustfmt::skip because rustfmt removes the 'where' claus on the associated type. | ||
| 185 | #[rustfmt::skip] | ||
| 186 | type ReadFuture<'a> where Self: 'a = impl Future<Output = Result<(), embassy_traits::uart::Error>> + 'a; | ||
| 187 | |||
| 188 | fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReadFuture<'a> { | ||
| 189 | self.read_dma(buf) | ||
| 190 | .map_err(|_| embassy_traits::uart::Error::Other) | ||
| 191 | } | ||
| 192 | } | ||
| 193 | |||
| 194 | pub struct State<'d, T: Instance>(StateStorage<StateInner<'d, T>>); | ||
| 195 | impl<'d, T: Instance> State<'d, T> { | ||
| 196 | pub fn new() -> Self { | ||
| 197 | Self(StateStorage::new()) | ||
| 198 | } | ||
| 199 | } | ||
| 200 | |||
| 201 | pub struct StateInner<'d, T: Instance> { | ||
| 202 | uart: Uart<'d, T, NoDma, NoDma>, | ||
| 203 | phantom: PhantomData<&'d mut T>, | ||
| 204 | |||
| 205 | rx_waker: WakerRegistration, | ||
| 206 | rx: RingBuffer<'d>, | ||
| 207 | |||
| 208 | tx_waker: WakerRegistration, | ||
| 209 | tx: RingBuffer<'d>, | ||
| 210 | } | ||
| 211 | |||
| 212 | unsafe impl<'d, T: Instance> Send for StateInner<'d, T> {} | ||
| 213 | unsafe impl<'d, T: Instance> Sync for StateInner<'d, T> {} | ||
| 214 | |||
| 215 | pub struct BufferedUart<'d, T: Instance> { | ||
| 216 | inner: PeripheralMutex<'d, StateInner<'d, T>>, | ||
| 217 | } | ||
| 218 | |||
| 219 | impl<'d, T: Instance> Unpin for BufferedUart<'d, T> {} | ||
| 220 | |||
| 221 | impl<'d, T: Instance> BufferedUart<'d, T> { | ||
| 222 | pub unsafe fn new( | ||
| 223 | state: &'d mut State<'d, T>, | ||
| 224 | uart: Uart<'d, T, NoDma, NoDma>, | ||
| 225 | irq: impl Unborrow<Target = T::Interrupt> + 'd, | ||
| 226 | tx_buffer: &'d mut [u8], | ||
| 227 | rx_buffer: &'d mut [u8], | ||
| 228 | ) -> BufferedUart<'d, T> { | ||
| 229 | unborrow!(irq); | ||
| 230 | |||
| 231 | let r = uart.inner.regs(); | ||
| 232 | r.cr1().modify(|w| { | ||
| 233 | w.set_rxneie(true); | ||
| 234 | w.set_idleie(true); | ||
| 235 | }); | ||
| 236 | |||
| 237 | Self { | ||
| 238 | inner: PeripheralMutex::new_unchecked(irq, &mut state.0, move || StateInner { | ||
| 239 | uart, | ||
| 240 | phantom: PhantomData, | ||
| 241 | tx: RingBuffer::new(tx_buffer), | ||
| 242 | tx_waker: WakerRegistration::new(), | ||
| 243 | |||
| 244 | rx: RingBuffer::new(rx_buffer), | ||
| 245 | rx_waker: WakerRegistration::new(), | ||
| 246 | }), | ||
| 247 | } | ||
| 248 | } | ||
| 249 | } | ||
| 250 | |||
| 251 | impl<'d, T: Instance> StateInner<'d, T> | ||
| 252 | where | ||
| 253 | Self: 'd, | ||
| 254 | { | ||
| 255 | fn on_rx(&mut self) { | ||
| 256 | let r = self.uart.inner.regs(); | ||
| 257 | unsafe { | ||
| 258 | let sr = r.isr().read(); | ||
| 259 | if sr.pe() { | ||
| 260 | r.icr().write(|w| { | ||
| 261 | w.set_pe(true); | ||
| 262 | }); | ||
| 263 | trace!("Parity error"); | ||
| 264 | } else if sr.fe() { | ||
| 265 | r.icr().write(|w| { | ||
| 266 | w.set_fe(true); | ||
| 267 | }); | ||
| 268 | trace!("Framing error"); | ||
| 269 | } else if sr.nf() { | ||
| 270 | r.icr().write(|w| { | ||
| 271 | w.set_nf(true); | ||
| 272 | }); | ||
| 273 | trace!("Noise error"); | ||
| 274 | } else if sr.ore() { | ||
| 275 | r.icr().write(|w| { | ||
| 276 | w.set_ore(true); | ||
| 277 | }); | ||
| 278 | trace!("Overrun error"); | ||
| 279 | } else if sr.rxne() { | ||
| 280 | let buf = self.rx.push_buf(); | ||
| 281 | if buf.is_empty() { | ||
| 282 | self.rx_waker.wake(); | ||
| 283 | } else { | ||
| 284 | buf[0] = r.rdr().read().0 as u8; | ||
| 285 | self.rx.push(1); | ||
| 286 | } | ||
| 287 | } else if sr.idle() { | ||
| 288 | r.icr().write(|w| { | ||
| 289 | w.set_idle(true); | ||
| 290 | }); | ||
| 291 | self.rx_waker.wake(); | ||
| 292 | }; | ||
| 293 | } | ||
| 294 | } | ||
| 295 | |||
| 296 | fn on_tx(&mut self) { | ||
| 297 | let r = self.uart.inner.regs(); | ||
| 298 | unsafe { | ||
| 299 | if r.isr().read().txe() { | ||
| 300 | let buf = self.tx.pop_buf(); | ||
| 301 | if !buf.is_empty() { | ||
| 302 | r.cr1().modify(|w| { | ||
| 303 | w.set_txeie(true); | ||
| 304 | }); | ||
| 305 | r.tdr().write_value(regs::Dr(buf[0].into())); | ||
| 306 | self.tx.pop(1); | ||
| 307 | self.tx_waker.wake(); | ||
| 308 | } else { | ||
| 309 | // Disable interrupt until we have something to transmit again | ||
| 310 | r.cr1().modify(|w| { | ||
| 311 | w.set_txeie(false); | ||
| 312 | }); | ||
| 313 | } | ||
| 314 | } | ||
| 315 | } | ||
| 316 | } | ||
| 317 | } | ||
| 318 | |||
| 319 | impl<'d, T: Instance> PeripheralState for StateInner<'d, T> | ||
| 320 | where | ||
| 321 | Self: 'd, | ||
| 322 | { | ||
| 323 | type Interrupt = T::Interrupt; | ||
| 324 | fn on_interrupt(&mut self) { | ||
| 325 | self.on_rx(); | ||
| 326 | self.on_tx(); | ||
| 327 | } | ||
| 328 | } | ||
| 329 | |||
| 330 | impl<'d, T: Instance> embassy::io::AsyncBufRead for BufferedUart<'d, T> { | ||
| 331 | fn poll_fill_buf( | ||
| 332 | mut self: Pin<&mut Self>, | ||
| 333 | cx: &mut Context<'_>, | ||
| 334 | ) -> Poll<Result<&[u8], embassy::io::Error>> { | ||
| 335 | self.inner.with(|state| { | ||
| 336 | compiler_fence(Ordering::SeqCst); | ||
| 337 | |||
| 338 | // We have data ready in buffer? Return it. | ||
| 339 | let buf = state.rx.pop_buf(); | ||
| 340 | if !buf.is_empty() { | ||
| 341 | let buf: &[u8] = buf; | ||
| 342 | // Safety: buffer lives as long as uart | ||
| 343 | let buf: &[u8] = unsafe { core::mem::transmute(buf) }; | ||
| 344 | return Poll::Ready(Ok(buf)); | ||
| 345 | } | ||
| 346 | |||
| 347 | state.rx_waker.register(cx.waker()); | ||
| 348 | Poll::<Result<&[u8], embassy::io::Error>>::Pending | ||
| 349 | }) | ||
| 350 | } | ||
| 351 | fn consume(mut self: Pin<&mut Self>, amt: usize) { | ||
| 352 | let signal = self.inner.with(|state| { | ||
| 353 | let full = state.rx.is_full(); | ||
| 354 | state.rx.pop(amt); | ||
| 355 | full | ||
| 356 | }); | ||
| 357 | if signal { | ||
| 358 | self.inner.pend(); | ||
| 359 | } | ||
| 360 | } | ||
| 361 | } | ||
| 362 | |||
| 363 | impl<'d, T: Instance> embassy::io::AsyncWrite for BufferedUart<'d, T> { | ||
| 364 | fn poll_write( | ||
| 365 | mut self: Pin<&mut Self>, | ||
| 366 | cx: &mut Context<'_>, | ||
| 367 | buf: &[u8], | ||
| 368 | ) -> Poll<Result<usize, embassy::io::Error>> { | ||
| 369 | let (poll, empty) = self.inner.with(|state| { | ||
| 370 | let empty = state.tx.is_empty(); | ||
| 371 | let tx_buf = state.tx.push_buf(); | ||
| 372 | if tx_buf.is_empty() { | ||
| 373 | state.tx_waker.register(cx.waker()); | ||
| 374 | return (Poll::Pending, empty); | ||
| 375 | } | ||
| 376 | |||
| 377 | let n = core::cmp::min(tx_buf.len(), buf.len()); | ||
| 378 | tx_buf[..n].copy_from_slice(&buf[..n]); | ||
| 379 | state.tx.push(n); | ||
| 380 | |||
| 381 | (Poll::Ready(Ok(n)), empty) | ||
| 382 | }); | ||
| 383 | if empty { | ||
| 384 | self.inner.pend(); | ||
| 385 | } | ||
| 386 | poll | ||
| 387 | } | ||
| 388 | } | ||
diff --git a/stm32-data b/stm32-data | |||
| Subproject 3e883bdff7fbb1f96be353d2c062be57ec8921a | Subproject 5506d27471c7e3297450127c3279f3dab96c94f | ||
