diff options
| author | Corey Schuhen <[email protected]> | 2024-03-24 08:08:12 +1000 |
|---|---|---|
| committer | Corey Schuhen <[email protected]> | 2024-03-28 09:32:13 +1000 |
| commit | 41b7e4a434c0d1fe1fc5d93afe76f8058aa411db (patch) | |
| tree | fe5430f70a9f641a351941f639bbcc149416eb0f | |
| parent | 26c739c2f93252e9dc476d69f591a84d44491787 (diff) | |
BXCAN: Create TxMode in order to support buffered TX.
| -rw-r--r-- | embassy-stm32/src/can/bxcan.rs | 130 | ||||
| -rw-r--r-- | embassy-stm32/src/can/fdcan.rs | 5 |
2 files changed, 120 insertions, 15 deletions
diff --git a/embassy-stm32/src/can/bxcan.rs b/embassy-stm32/src/can/bxcan.rs index 66f6e7067..45a3836c0 100644 --- a/embassy-stm32/src/can/bxcan.rs +++ b/embassy-stm32/src/can/bxcan.rs | |||
| @@ -17,7 +17,6 @@ use crate::rcc::RccPeripheral; | |||
| 17 | use crate::{interrupt, peripherals, Peripheral}; | 17 | use crate::{interrupt, peripherals, Peripheral}; |
| 18 | 18 | ||
| 19 | pub mod enums; | 19 | pub mod enums; |
| 20 | use enums::*; | ||
| 21 | pub mod frame; | 20 | pub mod frame; |
| 22 | pub mod util; | 21 | pub mod util; |
| 23 | 22 | ||
| @@ -49,8 +48,7 @@ impl<T: Instance> interrupt::typelevel::Handler<T::TXInterrupt> for TxInterruptH | |||
| 49 | v.set_rqcp(1, true); | 48 | v.set_rqcp(1, true); |
| 50 | v.set_rqcp(2, true); | 49 | v.set_rqcp(2, true); |
| 51 | }); | 50 | }); |
| 52 | 51 | T::state().tx_mode.on_interrupt::<T>(); | |
| 53 | T::state().tx_waker.wake(); | ||
| 54 | } | 52 | } |
| 55 | } | 53 | } |
| 56 | 54 | ||
| @@ -258,7 +256,7 @@ impl<'d, T: Instance> CanTx<'d, T> { | |||
| 258 | /// If the TX queue is full, this will wait until there is space, therefore exerting backpressure. | 256 | /// If the TX queue is full, this will wait until there is space, therefore exerting backpressure. |
| 259 | pub async fn write(&mut self, frame: &Frame) -> crate::can::bx::TransmitStatus { | 257 | pub async fn write(&mut self, frame: &Frame) -> crate::can::bx::TransmitStatus { |
| 260 | poll_fn(|cx| { | 258 | poll_fn(|cx| { |
| 261 | T::state().tx_waker.register(cx.waker()); | 259 | T::state().tx_mode.register(cx.waker()); |
| 262 | if let Ok(status) = self.tx.transmit(frame) { | 260 | if let Ok(status) = self.tx.transmit(frame) { |
| 263 | return Poll::Ready(status); | 261 | return Poll::Ready(status); |
| 264 | } | 262 | } |
| @@ -277,7 +275,7 @@ impl<'d, T: Instance> CanTx<'d, T> { | |||
| 277 | 275 | ||
| 278 | async fn flush_inner(mb: crate::can::bx::Mailbox) { | 276 | async fn flush_inner(mb: crate::can::bx::Mailbox) { |
| 279 | poll_fn(|cx| { | 277 | poll_fn(|cx| { |
| 280 | T::state().tx_waker.register(cx.waker()); | 278 | T::state().tx_mode.register(cx.waker()); |
| 281 | if T::regs().tsr().read().tme(mb.index()) { | 279 | if T::regs().tsr().read().tme(mb.index()) { |
| 282 | return Poll::Ready(()); | 280 | return Poll::Ready(()); |
| 283 | } | 281 | } |
| @@ -294,7 +292,7 @@ impl<'d, T: Instance> CanTx<'d, T> { | |||
| 294 | 292 | ||
| 295 | async fn flush_any_inner() { | 293 | async fn flush_any_inner() { |
| 296 | poll_fn(|cx| { | 294 | poll_fn(|cx| { |
| 297 | T::state().tx_waker.register(cx.waker()); | 295 | T::state().tx_mode.register(cx.waker()); |
| 298 | 296 | ||
| 299 | let tsr = T::regs().tsr().read(); | 297 | let tsr = T::regs().tsr().read(); |
| 300 | if tsr.tme(crate::can::bx::Mailbox::Mailbox0.index()) | 298 | if tsr.tme(crate::can::bx::Mailbox::Mailbox0.index()) |
| @@ -316,7 +314,7 @@ impl<'d, T: Instance> CanTx<'d, T> { | |||
| 316 | 314 | ||
| 317 | async fn flush_all_inner() { | 315 | async fn flush_all_inner() { |
| 318 | poll_fn(|cx| { | 316 | poll_fn(|cx| { |
| 319 | T::state().tx_waker.register(cx.waker()); | 317 | T::state().tx_mode.register(cx.waker()); |
| 320 | 318 | ||
| 321 | let tsr = T::regs().tsr().read(); | 319 | let tsr = T::regs().tsr().read(); |
| 322 | if tsr.tme(crate::can::bx::Mailbox::Mailbox0.index()) | 320 | if tsr.tme(crate::can::bx::Mailbox::Mailbox0.index()) |
| @@ -335,6 +333,62 @@ impl<'d, T: Instance> CanTx<'d, T> { | |||
| 335 | pub async fn flush_all(&self) { | 333 | pub async fn flush_all(&self) { |
| 336 | Self::flush_all_inner().await | 334 | Self::flush_all_inner().await |
| 337 | } | 335 | } |
| 336 | |||
| 337 | /// Return a buffered instance of driver. User must supply Buffers | ||
| 338 | pub fn buffered<const TX_BUF_SIZE: usize>( | ||
| 339 | self, | ||
| 340 | txb: &'static mut TxBuf<TX_BUF_SIZE>, | ||
| 341 | ) -> BufferedCanTx<'d, T, TX_BUF_SIZE> { | ||
| 342 | BufferedCanTx::new(self.tx, txb) | ||
| 343 | } | ||
| 344 | } | ||
| 345 | |||
| 346 | /// User supplied buffer for TX buffering | ||
| 347 | pub type TxBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, Frame, BUF_SIZE>; | ||
| 348 | |||
| 349 | /// CAN driver, transmit half. | ||
| 350 | pub struct BufferedCanTx<'d, T: Instance, const TX_BUF_SIZE: usize> { | ||
| 351 | _tx: crate::can::bx::Tx<BxcanInstance<'d, T>>, | ||
| 352 | tx_buf: &'static TxBuf<TX_BUF_SIZE>, | ||
| 353 | } | ||
| 354 | |||
| 355 | impl<'d, T: Instance, const TX_BUF_SIZE: usize> BufferedCanTx<'d, T, TX_BUF_SIZE> { | ||
| 356 | fn new(_tx: crate::can::bx::Tx<BxcanInstance<'d, T>>, tx_buf: &'static TxBuf<TX_BUF_SIZE>) -> Self { | ||
| 357 | Self { _tx, tx_buf }.setup() | ||
| 358 | } | ||
| 359 | |||
| 360 | fn setup(self) -> Self { | ||
| 361 | // We don't want interrupts being processed while we change modes. | ||
| 362 | critical_section::with(|_| unsafe { | ||
| 363 | let tx_inner = self::common::ClassicBufferedTxInner { | ||
| 364 | tx_receiver: self.tx_buf.receiver().into(), | ||
| 365 | }; | ||
| 366 | T::mut_state().tx_mode = TxMode::Buffered(tx_inner); | ||
| 367 | }); | ||
| 368 | self | ||
| 369 | } | ||
| 370 | |||
| 371 | /// Async write frame to TX buffer. | ||
| 372 | pub async fn write(&mut self, frame: &Frame) { | ||
| 373 | self.tx_buf.send(*frame).await; | ||
| 374 | T::TXInterrupt::pend(); // Wake for Tx | ||
| 375 | } | ||
| 376 | |||
| 377 | /// Returns a sender that can be used for sending CAN frames. | ||
| 378 | pub fn writer(&self) -> BufferedCanSender { | ||
| 379 | BufferedCanSender { | ||
| 380 | tx_buf: self.tx_buf.sender().into(), | ||
| 381 | waker: T::TXInterrupt::pend, | ||
| 382 | } | ||
| 383 | } | ||
| 384 | } | ||
| 385 | |||
| 386 | impl<'d, T: Instance, const TX_BUF_SIZE: usize> Drop for BufferedCanTx<'d, T, TX_BUF_SIZE> { | ||
| 387 | fn drop(&mut self) { | ||
| 388 | critical_section::with(|_| unsafe { | ||
| 389 | T::mut_state().tx_mode = TxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new()); | ||
| 390 | }); | ||
| 391 | } | ||
| 338 | } | 392 | } |
| 339 | 393 | ||
| 340 | /// CAN driver, receive half. | 394 | /// CAN driver, receive half. |
| @@ -365,7 +419,7 @@ impl<'d, T: Instance> CanRx<'d, T> { | |||
| 365 | T::state().rx_mode.wait_not_empty::<T>().await | 419 | T::state().rx_mode.wait_not_empty::<T>().await |
| 366 | } | 420 | } |
| 367 | 421 | ||
| 368 | /// Return a buffered instance of driver without CAN FD support. User must supply Buffers | 422 | /// Return a buffered instance of driver. User must supply Buffers |
| 369 | pub fn buffered<const RX_BUF_SIZE: usize>( | 423 | pub fn buffered<const RX_BUF_SIZE: usize>( |
| 370 | self, | 424 | self, |
| 371 | rxb: &'static mut RxBuf<RX_BUF_SIZE>, | 425 | rxb: &'static mut RxBuf<RX_BUF_SIZE>, |
| @@ -442,6 +496,14 @@ impl<'d, T: Instance, const RX_BUF_SIZE: usize> BufferedCanRx<'d, T, RX_BUF_SIZE | |||
| 442 | } | 496 | } |
| 443 | } | 497 | } |
| 444 | 498 | ||
| 499 | impl<'d, T: Instance, const RX_BUF_SIZE: usize> Drop for BufferedCanRx<'d, T, RX_BUF_SIZE> { | ||
| 500 | fn drop(&mut self) { | ||
| 501 | critical_section::with(|_| unsafe { | ||
| 502 | T::mut_state().rx_mode = RxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new()); | ||
| 503 | }); | ||
| 504 | } | ||
| 505 | } | ||
| 506 | |||
| 445 | use crate::can::bx::RxFifo; | 507 | use crate::can::bx::RxFifo; |
| 446 | 508 | ||
| 447 | impl<'d, T: Instance> Drop for Can<'d, T> { | 509 | impl<'d, T: Instance> Drop for Can<'d, T> { |
| @@ -568,18 +630,62 @@ impl RxMode { | |||
| 568 | } | 630 | } |
| 569 | } | 631 | } |
| 570 | } | 632 | } |
| 633 | |||
| 634 | enum TxMode { | ||
| 635 | NonBuffered(AtomicWaker), | ||
| 636 | Buffered(self::common::ClassicBufferedTxInner), | ||
| 637 | } | ||
| 638 | |||
| 639 | impl TxMode { | ||
| 640 | pub fn buffer_free<T: Instance>(&self) -> bool { | ||
| 641 | let tsr = T::regs().tsr().read(); | ||
| 642 | tsr.tme(crate::can::bx::Mailbox::Mailbox0.index()) | ||
| 643 | || tsr.tme(crate::can::bx::Mailbox::Mailbox1.index()) | ||
| 644 | || tsr.tme(crate::can::bx::Mailbox::Mailbox2.index()) | ||
| 645 | } | ||
| 646 | pub fn on_interrupt<T: Instance>(&self) { | ||
| 647 | match &T::state().tx_mode { | ||
| 648 | TxMode::NonBuffered(waker) => waker.wake(), | ||
| 649 | TxMode::Buffered(buf) => { | ||
| 650 | while self.buffer_free::<T>() { | ||
| 651 | match buf.tx_receiver.try_receive() { | ||
| 652 | Ok(frame) => { | ||
| 653 | let mut registers = crate::can::bx::Registers { canregs: T::regs() }; | ||
| 654 | _ = registers.transmit(&frame); | ||
| 655 | } | ||
| 656 | Err(_) => { | ||
| 657 | break; | ||
| 658 | } | ||
| 659 | } | ||
| 660 | } | ||
| 661 | } | ||
| 662 | } | ||
| 663 | } | ||
| 664 | |||
| 665 | fn register(&self, arg: &core::task::Waker) { | ||
| 666 | match self { | ||
| 667 | TxMode::NonBuffered(waker) => { | ||
| 668 | waker.register(arg); | ||
| 669 | } | ||
| 670 | _ => { | ||
| 671 | panic!("Bad mode"); | ||
| 672 | } | ||
| 673 | } | ||
| 674 | } | ||
| 675 | } | ||
| 676 | |||
| 571 | struct State { | 677 | struct State { |
| 572 | pub tx_waker: AtomicWaker, | ||
| 573 | pub err_waker: AtomicWaker, | ||
| 574 | pub(crate) rx_mode: RxMode, | 678 | pub(crate) rx_mode: RxMode, |
| 679 | pub(crate) tx_mode: TxMode, | ||
| 680 | pub err_waker: AtomicWaker, | ||
| 575 | } | 681 | } |
| 576 | 682 | ||
| 577 | impl State { | 683 | impl State { |
| 578 | pub const fn new() -> Self { | 684 | pub const fn new() -> Self { |
| 579 | Self { | 685 | Self { |
| 580 | tx_waker: AtomicWaker::new(), | ||
| 581 | err_waker: AtomicWaker::new(), | ||
| 582 | rx_mode: RxMode::NonBuffered(AtomicWaker::new()), | 686 | rx_mode: RxMode::NonBuffered(AtomicWaker::new()), |
| 687 | tx_mode: TxMode::NonBuffered(AtomicWaker::new()), | ||
| 688 | err_waker: AtomicWaker::new(), | ||
| 583 | } | 689 | } |
| 584 | } | 690 | } |
| 585 | } | 691 | } |
diff --git a/embassy-stm32/src/can/fdcan.rs b/embassy-stm32/src/can/fdcan.rs index 42c9bd9f6..e58d8c0ec 100644 --- a/embassy-stm32/src/can/fdcan.rs +++ b/embassy-stm32/src/can/fdcan.rs | |||
| @@ -507,7 +507,7 @@ pub struct BufferedCanFd<'d, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF | |||
| 507 | /// Sender that can be used for sending CAN frames. | 507 | /// Sender that can be used for sending CAN frames. |
| 508 | #[derive(Copy, Clone)] | 508 | #[derive(Copy, Clone)] |
| 509 | pub struct BufferedFdCanSender { | 509 | pub struct BufferedFdCanSender { |
| 510 | tx_buf: embassy_sync::channel::DynamicSender<'static, FdFrame>, | 510 | tx_buf: DynamicSender<'static, FdFrame>, |
| 511 | waker: fn(), | 511 | waker: fn(), |
| 512 | } | 512 | } |
| 513 | 513 | ||
| @@ -532,8 +532,7 @@ impl BufferedFdCanSender { | |||
| 532 | } | 532 | } |
| 533 | 533 | ||
| 534 | /// Receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver. | 534 | /// Receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver. |
| 535 | pub type BufferedFdCanReceiver = | 535 | pub type BufferedFdCanReceiver = DynamicReceiver<'static, Result<(FdFrame, Timestamp), BusError>>; |
| 536 | embassy_sync::channel::DynamicReceiver<'static, Result<(FdFrame, Timestamp), BusError>>; | ||
| 537 | 536 | ||
| 538 | impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> | 537 | impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> |
| 539 | BufferedCanFd<'d, T, TX_BUF_SIZE, RX_BUF_SIZE> | 538 | BufferedCanFd<'d, T, TX_BUF_SIZE, RX_BUF_SIZE> |
