aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCorey Schuhen <[email protected]>2024-03-24 08:08:12 +1000
committerCorey Schuhen <[email protected]>2024-03-28 09:32:13 +1000
commit41b7e4a434c0d1fe1fc5d93afe76f8058aa411db (patch)
treefe5430f70a9f641a351941f639bbcc149416eb0f
parent26c739c2f93252e9dc476d69f591a84d44491787 (diff)
BXCAN: Create TxMode in order to support buffered TX.
-rw-r--r--embassy-stm32/src/can/bxcan.rs130
-rw-r--r--embassy-stm32/src/can/fdcan.rs5
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;
17use crate::{interrupt, peripherals, Peripheral}; 17use crate::{interrupt, peripherals, Peripheral};
18 18
19pub mod enums; 19pub mod enums;
20use enums::*;
21pub mod frame; 20pub mod frame;
22pub mod util; 21pub 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
347pub type TxBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, Frame, BUF_SIZE>;
348
349/// CAN driver, transmit half.
350pub 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
355impl<'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
386impl<'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
499impl<'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
445use crate::can::bx::RxFifo; 507use crate::can::bx::RxFifo;
446 508
447impl<'d, T: Instance> Drop for Can<'d, T> { 509impl<'d, T: Instance> Drop for Can<'d, T> {
@@ -568,18 +630,62 @@ impl RxMode {
568 } 630 }
569 } 631 }
570} 632}
633
634enum TxMode {
635 NonBuffered(AtomicWaker),
636 Buffered(self::common::ClassicBufferedTxInner),
637}
638
639impl 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
571struct State { 677struct 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
577impl State { 683impl 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)]
509pub struct BufferedFdCanSender { 509pub 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.
535pub type BufferedFdCanReceiver = 535pub type BufferedFdCanReceiver = DynamicReceiver<'static, Result<(FdFrame, Timestamp), BusError>>;
536 embassy_sync::channel::DynamicReceiver<'static, Result<(FdFrame, Timestamp), BusError>>;
537 536
538impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> 537impl<'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>