aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCorey Schuhen <[email protected]>2024-02-17 18:12:47 +1000
committerCorey Schuhen <[email protected]>2024-02-17 18:26:57 +1000
commit5ad291b708528b5772d6ebcc9309fbd3f8a002c8 (patch)
treed591f9170b2e63f054c85a7650aba70a52dc8c0a
parent91c75c92a0e67c93550a163ae62b22a652bf2012 (diff)
Add a buffered mode.
-rw-r--r--embassy-stm32/src/can/fdcan.rs233
-rw-r--r--examples/stm32g4/src/bin/can.rs97
2 files changed, 323 insertions, 7 deletions
diff --git a/embassy-stm32/src/can/fdcan.rs b/embassy-stm32/src/can/fdcan.rs
index 42ce73ded..3ae330e14 100644
--- a/embassy-stm32/src/can/fdcan.rs
+++ b/embassy-stm32/src/can/fdcan.rs
@@ -5,6 +5,8 @@ use core::task::Poll;
5 5
6pub mod fd; 6pub mod fd;
7use embassy_hal_internal::{into_ref, PeripheralRef}; 7use embassy_hal_internal::{into_ref, PeripheralRef};
8use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
9use embassy_sync::channel::Channel;
8use fd::config::*; 10use fd::config::*;
9use fd::filter::*; 11use fd::filter::*;
10 12
@@ -49,6 +51,26 @@ impl<T: Instance> interrupt::typelevel::Handler<T::IT0Interrupt> for IT0Interrup
49 51
50 match &T::state().tx_mode { 52 match &T::state().tx_mode {
51 sealed::TxMode::NonBuffered(waker) => waker.wake(), 53 sealed::TxMode::NonBuffered(waker) => waker.wake(),
54 sealed::TxMode::ClassicBuffered(buf) => {
55 if !T::registers().tx_queue_is_full() {
56 match buf.tx_receiver.try_receive() {
57 Ok(frame) => {
58 _ = T::registers().write_classic(&frame);
59 }
60 Err(_) => {}
61 }
62 }
63 }
64 sealed::TxMode::FdBuffered(buf) => {
65 if !T::registers().tx_queue_is_full() {
66 match buf.tx_receiver.try_receive() {
67 Ok(frame) => {
68 _ = T::registers().write_fd(&frame);
69 }
70 Err(_) => {}
71 }
72 }
73 }
52 } 74 }
53 } 75 }
54 76
@@ -405,6 +427,179 @@ where
405 ) 427 )
406 } 428 }
407 429
430 /// Return a buffered instance of driver without CAN FD support. User must supply Buffers
431 pub fn buffered<const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize>(
432 &self,
433 tx_buf: &'static mut TxBuf<TX_BUF_SIZE>,
434 rxb: &'static mut RxBuf<RX_BUF_SIZE>,
435 ) -> BufferedCan<'d, T, M, TX_BUF_SIZE, RX_BUF_SIZE> {
436 BufferedCan::new(PhantomData::<T>, T::regs(), self._mode, tx_buf, rxb)
437 }
438
439 /// Return a buffered instance of driver with CAN FD support. User must supply Buffers
440 pub fn buffered_fd<const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize>(
441 &self,
442 tx_buf: &'static mut TxFdBuf<TX_BUF_SIZE>,
443 rxb: &'static mut RxFdBuf<RX_BUF_SIZE>,
444 ) -> BufferedCanFd<'d, T, M, TX_BUF_SIZE, RX_BUF_SIZE> {
445 BufferedCanFd::new(PhantomData::<T>, T::regs(), self._mode, tx_buf, rxb)
446 }
447}
448
449/// User supplied buffer for RX Buffering
450pub type RxBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, (ClassicFrame, Timestamp), BUF_SIZE>;
451
452/// User supplied buffer for TX buffering
453pub type TxBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, ClassicFrame, BUF_SIZE>;
454
455/// Buffered FDCAN Instance
456#[allow(dead_code)]
457pub struct BufferedCan<'d, T: Instance, M: FdcanOperatingMode, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> {
458 _instance1: PhantomData<T>,
459 _instance2: &'d crate::pac::can::Fdcan,
460 _mode: PhantomData<M>,
461 tx_buf: &'static TxBuf<TX_BUF_SIZE>,
462 rx_buf: &'static RxBuf<RX_BUF_SIZE>,
463}
464
465impl<'c, 'd, T: Instance, M: Transmit, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize>
466 BufferedCan<'d, T, M, TX_BUF_SIZE, RX_BUF_SIZE>
467where
468 M: FdcanOperatingMode,
469{
470 fn new(
471 _instance1: PhantomData<T>,
472 _instance2: &'d crate::pac::can::Fdcan,
473 _mode: PhantomData<M>,
474 tx_buf: &'static TxBuf<TX_BUF_SIZE>,
475 rx_buf: &'static RxBuf<RX_BUF_SIZE>,
476 ) -> Self {
477 BufferedCan {
478 _instance1,
479 _instance2,
480 _mode,
481 tx_buf,
482 rx_buf,
483 }
484 .setup()
485 }
486
487 fn setup(self) -> Self {
488 // We don't want interrupts being processed while we change modes.
489 critical_section::with(|_| unsafe {
490 let rx_inner = sealed::ClassicBufferedRxInner {
491 rx_sender: self.rx_buf.sender().into(),
492 };
493 let tx_inner = sealed::ClassicBufferedTxInner {
494 tx_receiver: self.tx_buf.receiver().into(),
495 };
496 T::mut_state().rx_mode = sealed::RxMode::ClassicBuffered(rx_inner);
497 T::mut_state().tx_mode = sealed::TxMode::ClassicBuffered(tx_inner);
498 });
499 self
500 }
501
502 /// Async write frame to TX buffer.
503 pub async fn write(&mut self, frame: ClassicFrame) {
504 self.tx_buf.send(frame).await;
505 T::IT0Interrupt::pend(); // Wake for Tx
506 }
507
508 /// Async read frame from RX buffer.
509 pub async fn read(&mut self) -> Result<(ClassicFrame, Timestamp), BusError> {
510 Ok(self.rx_buf.receive().await)
511 }
512}
513
514impl<'c, 'd, T: Instance, M, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> Drop
515 for BufferedCan<'d, T, M, TX_BUF_SIZE, RX_BUF_SIZE>
516where
517 M: FdcanOperatingMode,
518{
519 fn drop(&mut self) {
520 critical_section::with(|_| unsafe {
521 T::mut_state().rx_mode = sealed::RxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new());
522 T::mut_state().tx_mode = sealed::TxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new());
523 });
524 }
525}
526
527/// User supplied buffer for RX Buffering
528pub type RxFdBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, (FdFrame, Timestamp), BUF_SIZE>;
529
530/// User supplied buffer for TX buffering
531pub type TxFdBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, FdFrame, BUF_SIZE>;
532
533/// Buffered FDCAN Instance
534#[allow(dead_code)]
535pub struct BufferedCanFd<'d, T: Instance, M: FdcanOperatingMode, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> {
536 _instance1: PhantomData<T>,
537 _instance2: &'d crate::pac::can::Fdcan,
538 _mode: PhantomData<M>,
539 tx_buf: &'static TxFdBuf<TX_BUF_SIZE>,
540 rx_buf: &'static RxFdBuf<RX_BUF_SIZE>,
541}
542
543impl<'c, 'd, T: Instance, M: Transmit, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize>
544 BufferedCanFd<'d, T, M, TX_BUF_SIZE, RX_BUF_SIZE>
545where
546 M: FdcanOperatingMode,
547{
548 fn new(
549 _instance1: PhantomData<T>,
550 _instance2: &'d crate::pac::can::Fdcan,
551 _mode: PhantomData<M>,
552 tx_buf: &'static TxFdBuf<TX_BUF_SIZE>,
553 rx_buf: &'static RxFdBuf<RX_BUF_SIZE>,
554 ) -> Self {
555 BufferedCanFd {
556 _instance1,
557 _instance2,
558 _mode,
559 tx_buf,
560 rx_buf,
561 }
562 .setup()
563 }
564
565 fn setup(self) -> Self {
566 // We don't want interrupts being processed while we change modes.
567 critical_section::with(|_| unsafe {
568 let rx_inner = sealed::FdBufferedRxInner {
569 rx_sender: self.rx_buf.sender().into(),
570 };
571 let tx_inner = sealed::FdBufferedTxInner {
572 tx_receiver: self.tx_buf.receiver().into(),
573 };
574 T::mut_state().rx_mode = sealed::RxMode::FdBuffered(rx_inner);
575 T::mut_state().tx_mode = sealed::TxMode::FdBuffered(tx_inner);
576 });
577 self
578 }
579
580 /// Async write frame to TX buffer.
581 pub async fn write(&mut self, frame: FdFrame) {
582 self.tx_buf.send(frame).await;
583 T::IT0Interrupt::pend(); // Wake for Tx
584 }
585
586 /// Async read frame from RX buffer.
587 pub async fn read(&mut self) -> Result<(FdFrame, Timestamp), BusError> {
588 Ok(self.rx_buf.receive().await)
589 }
590}
591
592impl<'c, 'd, T: Instance, M, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> Drop
593 for BufferedCanFd<'d, T, M, TX_BUF_SIZE, RX_BUF_SIZE>
594where
595 M: FdcanOperatingMode,
596{
597 fn drop(&mut self) {
598 critical_section::with(|_| unsafe {
599 T::mut_state().rx_mode = sealed::RxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new());
600 T::mut_state().tx_mode = sealed::TxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new());
601 });
602 }
408} 603}
409 604
410/// FDCAN Rx only Instance 605/// FDCAN Rx only Instance
@@ -456,18 +651,39 @@ pub(crate) mod sealed {
456 use core::future::poll_fn; 651 use core::future::poll_fn;
457 use core::task::Poll; 652 use core::task::Poll;
458 653
654 use embassy_sync::channel::{DynamicReceiver, DynamicSender};
459 use embassy_sync::waitqueue::AtomicWaker; 655 use embassy_sync::waitqueue::AtomicWaker;
460 656
461 use crate::can::_version::{BusError, Timestamp}; 657 use crate::can::_version::{BusError, Timestamp};
462 use crate::can::frame::{ClassicFrame, FdFrame}; 658 use crate::can::frame::{ClassicFrame, FdFrame};
659
660 pub struct ClassicBufferedRxInner {
661 pub rx_sender: DynamicSender<'static, (ClassicFrame, Timestamp)>,
662 }
663 pub struct ClassicBufferedTxInner {
664 pub tx_receiver: DynamicReceiver<'static, ClassicFrame>,
665 }
666
667 pub struct FdBufferedRxInner {
668 pub rx_sender: DynamicSender<'static, (FdFrame, Timestamp)>,
669 }
670 pub struct FdBufferedTxInner {
671 pub tx_receiver: DynamicReceiver<'static, FdFrame>,
672 }
673
463 pub enum RxMode { 674 pub enum RxMode {
464 NonBuffered(AtomicWaker), 675 NonBuffered(AtomicWaker),
676 ClassicBuffered(ClassicBufferedRxInner),
677 FdBuffered(FdBufferedRxInner),
465 } 678 }
466 679
467 impl RxMode { 680 impl RxMode {
468 pub fn register(&self, arg: &core::task::Waker) { 681 pub fn register(&self, arg: &core::task::Waker) {
469 match self { 682 match self {
470 RxMode::NonBuffered(waker) => waker.register(arg), 683 RxMode::NonBuffered(waker) => waker.register(arg),
684 _ => {
685 panic!("Bad Mode")
686 }
471 } 687 }
472 } 688 }
473 689
@@ -477,6 +693,18 @@ pub(crate) mod sealed {
477 RxMode::NonBuffered(waker) => { 693 RxMode::NonBuffered(waker) => {
478 waker.wake(); 694 waker.wake();
479 } 695 }
696 RxMode::ClassicBuffered(buf) => {
697 if let Some(r) = T::registers().read_classic(fifonr) {
698 let ts = T::calc_timestamp(T::state().ns_per_timer_tick, r.1);
699 let _ = buf.rx_sender.try_send((r.0, ts));
700 }
701 }
702 RxMode::FdBuffered(buf) => {
703 if let Some(r) = T::registers().read_fd(fifonr) {
704 let ts = T::calc_timestamp(T::state().ns_per_timer_tick, r.1);
705 let _ = buf.rx_sender.try_send((r.0, ts));
706 }
707 }
480 } 708 }
481 } 709 }
482 710
@@ -523,6 +751,8 @@ pub(crate) mod sealed {
523 751
524 pub enum TxMode { 752 pub enum TxMode {
525 NonBuffered(AtomicWaker), 753 NonBuffered(AtomicWaker),
754 ClassicBuffered(ClassicBufferedTxInner),
755 FdBuffered(FdBufferedTxInner),
526 } 756 }
527 757
528 impl TxMode { 758 impl TxMode {
@@ -531,6 +761,9 @@ pub(crate) mod sealed {
531 TxMode::NonBuffered(waker) => { 761 TxMode::NonBuffered(waker) => {
532 waker.register(arg); 762 waker.register(arg);
533 } 763 }
764 _ => {
765 panic!("Bad mode");
766 }
534 } 767 }
535 } 768 }
536 769
diff --git a/examples/stm32g4/src/bin/can.rs b/examples/stm32g4/src/bin/can.rs
index 5ff4f0ef0..043ca7144 100644
--- a/examples/stm32g4/src/bin/can.rs
+++ b/examples/stm32g4/src/bin/can.rs
@@ -5,6 +5,7 @@ use embassy_executor::Spawner;
5use embassy_stm32::peripherals::*; 5use embassy_stm32::peripherals::*;
6use embassy_stm32::{bind_interrupts, can, Config}; 6use embassy_stm32::{bind_interrupts, can, Config};
7use embassy_time::Timer; 7use embassy_time::Timer;
8use static_cell::StaticCell;
8use {defmt_rtt as _, panic_probe as _}; 9use {defmt_rtt as _, panic_probe as _};
9 10
10bind_interrupts!(struct Irqs { 11bind_interrupts!(struct Irqs {
@@ -28,13 +29,17 @@ async fn main(_spawner: Spawner) {
28 // 250k bps 29 // 250k bps
29 can.set_bitrate(250_000); 30 can.set_bitrate(250_000);
30 31
32 let use_fd = false;
33
31 // 1M bps 34 // 1M bps
32 can.set_fd_data_bitrate(1_000_000, false); 35 if use_fd {
36 can.set_fd_data_bitrate(1_000_000, false);
37 }
33 38
34 info!("Configured"); 39 info!("Configured");
35 40
36 //let mut can = can.into_normal_mode(); 41 let mut can = can.into_normal_mode();
37 let mut can = can.into_internal_loopback_mode(); 42 //let mut can = can.into_internal_loopback_mode();
38 43
39 let mut i = 0; 44 let mut i = 0;
40 let mut last_read_ts = embassy_time::Instant::now(); 45 let mut last_read_ts = embassy_time::Instant::now();
@@ -68,11 +73,17 @@ async fn main(_spawner: Spawner) {
68 } 73 }
69 74
70 // Use the FD API's even if we don't get FD packets. 75 // Use the FD API's even if we don't get FD packets.
71 loop {
72 let frame = can::frame::FdFrame::new_extended(0x123456F, &[i; 16]).unwrap();
73 info!("Writing frame using FD API");
74 76
75 _ = can.write_fd(&frame).await; 77 loop {
78 if use_fd {
79 let frame = can::frame::FdFrame::new_extended(0x123456F, &[i; 16]).unwrap();
80 info!("Writing frame using FD API");
81 _ = can.write_fd(&frame).await;
82 } else {
83 let frame = can::frame::FdFrame::new_extended(0x123456F, &[i; 8]).unwrap();
84 info!("Writing frame using FD API");
85 _ = can.write_fd(&frame).await;
86 }
76 87
77 match can.read_fd().await { 88 match can.read_fd().await {
78 Ok((rx_frame, ts)) => { 89 Ok((rx_frame, ts)) => {
@@ -96,6 +107,7 @@ async fn main(_spawner: Spawner) {
96 } 107 }
97 } 108 }
98 109
110 i = 0;
99 let (mut tx, mut rx) = can.split(); 111 let (mut tx, mut rx) = can.split();
100 // With split 112 // With split
101 loop { 113 loop {
@@ -120,5 +132,76 @@ async fn main(_spawner: Spawner) {
120 Timer::after_millis(250).await; 132 Timer::after_millis(250).await;
121 133
122 i += 1; 134 i += 1;
135
136 if i > 2 {
137 break;
138 }
139 }
140
141 let can = can::Fdcan::join(tx, rx);
142
143 info!("\n\n\nBuffered\n");
144 if use_fd {
145 static TX_BUF: StaticCell<can::TxFdBuf<8>> = StaticCell::new();
146 static RX_BUF: StaticCell<can::RxFdBuf<10>> = StaticCell::new();
147 let mut can = can.buffered_fd(
148 TX_BUF.init(can::TxFdBuf::<8>::new()),
149 RX_BUF.init(can::RxFdBuf::<10>::new()),
150 );
151 loop {
152 let frame = can::frame::FdFrame::new_extended(0x123456F, &[i; 16]).unwrap();
153 info!("Writing frame");
154
155 _ = can.write(frame).await;
156
157 match can.read().await {
158 Ok((rx_frame, ts)) => {
159 let delta = (ts - last_read_ts).as_millis();
160 last_read_ts = ts;
161 info!(
162 "Rx: {} {:02x} --- {}ms",
163 rx_frame.header().len(),
164 rx_frame.data()[0..rx_frame.header().len() as usize],
165 delta,
166 )
167 }
168 Err(_err) => error!("Error in frame"),
169 }
170
171 Timer::after_millis(250).await;
172
173 i += 1;
174 }
175 } else {
176 static TX_BUF: StaticCell<can::TxBuf<8>> = StaticCell::new();
177 static RX_BUF: StaticCell<can::RxBuf<10>> = StaticCell::new();
178 let mut can = can.buffered(
179 TX_BUF.init(can::TxBuf::<8>::new()),
180 RX_BUF.init(can::RxBuf::<10>::new()),
181 );
182 loop {
183 let frame = can::frame::ClassicFrame::new_extended(0x123456F, &[i; 8]).unwrap();
184 info!("Writing frame");
185
186 _ = can.write(frame).await;
187
188 match can.read().await {
189 Ok((rx_frame, ts)) => {
190 let delta = (ts - last_read_ts).as_millis();
191 last_read_ts = ts;
192 info!(
193 "Rx: {} {:02x} --- {}ms",
194 rx_frame.header().len(),
195 rx_frame.data()[0..rx_frame.header().len() as usize],
196 delta,
197 )
198 }
199 Err(_err) => error!("Error in frame"),
200 }
201
202 Timer::after_millis(250).await;
203
204 i += 1;
205 }
123 } 206 }
124} 207}