aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorxoviat <[email protected]>2023-07-05 23:27:53 +0000
committerGitHub <[email protected]>2023-07-05 23:27:53 +0000
commit864202a23a1fa4362445d8f0b2fcda5003e38131 (patch)
treed067a7bb0841fdf3e8dba6e0d9f0b13cab59b6ee
parenta77fb0f630be9c7158f81e4b0ca7bd5e88d56dd0 (diff)
parenta088c4bee6e26947fd8e4d32a5604e47de293ba1 (diff)
Merge pull request #1578 from schphil/can-split
stm32 can split method
-rw-r--r--embassy-stm32/src/can/bxcan.rs89
-rw-r--r--examples/stm32f4/src/bin/can.rs18
-rw-r--r--examples/stm32f7/src/bin/can.rs66
-rw-r--r--tests/stm32/src/bin/can.rs7
4 files changed, 165 insertions, 15 deletions
diff --git a/embassy-stm32/src/can/bxcan.rs b/embassy-stm32/src/can/bxcan.rs
index 73861776a..5a0153464 100644
--- a/embassy-stm32/src/can/bxcan.rs
+++ b/embassy-stm32/src/can/bxcan.rs
@@ -1,3 +1,4 @@
1use core::cell::{RefCell, RefMut};
1use core::future::poll_fn; 2use core::future::poll_fn;
2use core::marker::PhantomData; 3use core::marker::PhantomData;
3use core::ops::{Deref, DerefMut}; 4use core::ops::{Deref, DerefMut};
@@ -72,7 +73,7 @@ impl<T: Instance> interrupt::typelevel::Handler<T::SCEInterrupt> for SceInterrup
72} 73}
73 74
74pub struct Can<'d, T: Instance> { 75pub struct Can<'d, T: Instance> {
75 can: bxcan::Can<BxcanInstance<'d, T>>, 76 pub can: RefCell<bxcan::Can<BxcanInstance<'d, T>>>,
76} 77}
77 78
78#[derive(Debug)] 79#[derive(Debug)]
@@ -147,19 +148,24 @@ impl<'d, T: Instance> Can<'d, T> {
147 tx.set_as_af(tx.af_num(), AFType::OutputPushPull); 148 tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
148 149
149 let can = bxcan::Can::builder(BxcanInstance(peri)).leave_disabled(); 150 let can = bxcan::Can::builder(BxcanInstance(peri)).leave_disabled();
150 Self { can } 151 let can_ref_cell = RefCell::new(can);
152 Self { can: can_ref_cell }
151 } 153 }
152 154
153 pub fn set_bitrate(&mut self, bitrate: u32) { 155 pub fn set_bitrate(&mut self, bitrate: u32) {
154 let bit_timing = Self::calc_bxcan_timings(T::frequency(), bitrate).unwrap(); 156 let bit_timing = Self::calc_bxcan_timings(T::frequency(), bitrate).unwrap();
155 self.can.modify_config().set_bit_timing(bit_timing).leave_disabled(); 157 self.can
158 .borrow_mut()
159 .modify_config()
160 .set_bit_timing(bit_timing)
161 .leave_disabled();
156 } 162 }
157 163
158 /// Queues the message to be sent but exerts backpressure 164 /// Queues the message to be sent but exerts backpressure
159 pub async fn write(&mut self, frame: &Frame) -> bxcan::TransmitStatus { 165 pub async fn write(&mut self, frame: &Frame) -> bxcan::TransmitStatus {
160 poll_fn(|cx| { 166 poll_fn(|cx| {
161 T::state().tx_waker.register(cx.waker()); 167 T::state().tx_waker.register(cx.waker());
162 if let Ok(status) = self.can.transmit(frame) { 168 if let Ok(status) = self.can.borrow_mut().transmit(frame) {
163 return Poll::Ready(status); 169 return Poll::Ready(status);
164 } 170 }
165 171
@@ -341,6 +347,79 @@ impl<'d, T: Instance> Can<'d, T> {
341 // Pack into BTR register values 347 // Pack into BTR register values
342 Some((sjw - 1) << 24 | (bs1 as u32 - 1) << 16 | (bs2 as u32 - 1) << 20 | (prescaler as u32 - 1)) 348 Some((sjw - 1) << 24 | (bs1 as u32 - 1) << 16 | (bs2 as u32 - 1) << 20 | (prescaler as u32 - 1))
343 } 349 }
350
351 pub fn split<'c>(&'c self) -> (CanTx<'c, 'd, T>, CanRx<'c, 'd, T>) {
352 (CanTx { can: &self.can }, CanRx { can: &self.can })
353 }
354
355 pub fn as_mut(&self) -> RefMut<'_, bxcan::Can<BxcanInstance<'d, T>>> {
356 self.can.borrow_mut()
357 }
358}
359
360pub struct CanTx<'c, 'd, T: Instance> {
361 can: &'c RefCell<bxcan::Can<BxcanInstance<'d, T>>>,
362}
363
364impl<'c, 'd, T: Instance> CanTx<'c, 'd, T> {
365 pub async fn write(&mut self, frame: &Frame) -> bxcan::TransmitStatus {
366 poll_fn(|cx| {
367 T::state().tx_waker.register(cx.waker());
368 if let Ok(status) = self.can.borrow_mut().transmit(frame) {
369 return Poll::Ready(status);
370 }
371
372 Poll::Pending
373 })
374 .await
375 }
376
377 pub async fn flush(&self, mb: bxcan::Mailbox) {
378 poll_fn(|cx| {
379 T::state().tx_waker.register(cx.waker());
380 if T::regs().tsr().read().tme(mb.index()) {
381 return Poll::Ready(());
382 }
383
384 Poll::Pending
385 })
386 .await;
387 }
388}
389
390#[allow(dead_code)]
391pub struct CanRx<'c, 'd, T: Instance> {
392 can: &'c RefCell<bxcan::Can<BxcanInstance<'d, T>>>,
393}
394
395impl<'c, 'd, T: Instance> CanRx<'c, 'd, T> {
396 pub async fn read(&mut self) -> Result<(u16, bxcan::Frame), BusError> {
397 poll_fn(|cx| {
398 T::state().err_waker.register(cx.waker());
399 if let Poll::Ready((time, frame)) = T::state().rx_queue.recv().poll_unpin(cx) {
400 return Poll::Ready(Ok((time, frame)));
401 } else if let Some(err) = self.curr_error() {
402 return Poll::Ready(Err(err));
403 }
404
405 Poll::Pending
406 })
407 .await
408 }
409
410 fn curr_error(&self) -> Option<BusError> {
411 let err = { T::regs().esr().read() };
412 if err.boff() {
413 return Some(BusError::BusOff);
414 } else if err.epvf() {
415 return Some(BusError::BusPassive);
416 } else if err.ewgf() {
417 return Some(BusError::BusWarning);
418 } else if let Some(err) = err.lec().into_bus_err() {
419 return Some(err);
420 }
421 None
422 }
344} 423}
345 424
346enum RxFifo { 425enum RxFifo {
@@ -358,7 +437,7 @@ impl<'d, T: Instance> Drop for Can<'d, T> {
358} 437}
359 438
360impl<'d, T: Instance> Deref for Can<'d, T> { 439impl<'d, T: Instance> Deref for Can<'d, T> {
361 type Target = bxcan::Can<BxcanInstance<'d, T>>; 440 type Target = RefCell<bxcan::Can<BxcanInstance<'d, T>>>;
362 441
363 fn deref(&self) -> &Self::Target { 442 fn deref(&self) -> &Self::Target {
364 &self.can 443 &self.can
diff --git a/examples/stm32f4/src/bin/can.rs b/examples/stm32f4/src/bin/can.rs
index da8955053..08bed88db 100644
--- a/examples/stm32f4/src/bin/can.rs
+++ b/examples/stm32f4/src/bin/can.rs
@@ -2,8 +2,8 @@
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)] 3#![feature(type_alias_impl_trait)]
4 4
5use cortex_m_rt::entry;
6use defmt::*; 5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_stm32::bind_interrupts; 7use embassy_stm32::bind_interrupts;
8use embassy_stm32::can::bxcan::filter::Mask32; 8use embassy_stm32::can::bxcan::filter::Mask32;
9use embassy_stm32::can::bxcan::{Fifo, Frame, StandardId}; 9use embassy_stm32::can::bxcan::{Fifo, Frame, StandardId};
@@ -19,8 +19,8 @@ bind_interrupts!(struct Irqs {
19 CAN1_TX => TxInterruptHandler<CAN1>; 19 CAN1_TX => TxInterruptHandler<CAN1>;
20}); 20});
21 21
22#[entry] 22#[embassy_executor::main]
23fn main() -> ! { 23async fn main(_spawner: Spawner) {
24 info!("Hello World!"); 24 info!("Hello World!");
25 25
26 let mut p = embassy_stm32::init(Default::default()); 26 let mut p = embassy_stm32::init(Default::default());
@@ -34,9 +34,12 @@ fn main() -> ! {
34 34
35 let mut can = Can::new(p.CAN1, p.PA11, p.PA12, Irqs); 35 let mut can = Can::new(p.CAN1, p.PA11, p.PA12, Irqs);
36 36
37 can.modify_filters().enable_bank(0, Fifo::Fifo0, Mask32::accept_all()); 37 can.as_mut()
38 .modify_filters()
39 .enable_bank(0, Fifo::Fifo0, Mask32::accept_all());
38 40
39 can.modify_config() 41 can.as_mut()
42 .modify_config()
40 .set_bit_timing(0x001c0003) // http://www.bittiming.can-wiki.info/ 43 .set_bit_timing(0x001c0003) // http://www.bittiming.can-wiki.info/
41 .set_loopback(true) // Receive own frames 44 .set_loopback(true) // Receive own frames
42 .set_silent(true) 45 .set_silent(true)
@@ -45,9 +48,8 @@ fn main() -> ! {
45 let mut i: u8 = 0; 48 let mut i: u8 = 0;
46 loop { 49 loop {
47 let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), [i]); 50 let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), [i]);
48 unwrap!(nb::block!(can.transmit(&tx_frame))); 51 can.write(&tx_frame).await;
49 while !can.is_transmitter_idle() {} 52 let (_, rx_frame) = can.read().await.unwrap();
50 let rx_frame = unwrap!(nb::block!(can.receive()));
51 info!("loopback frame {=u8}", unwrap!(rx_frame.data())[0]); 53 info!("loopback frame {=u8}", unwrap!(rx_frame.data())[0]);
52 i += 1; 54 i += 1;
53 } 55 }
diff --git a/examples/stm32f7/src/bin/can.rs b/examples/stm32f7/src/bin/can.rs
new file mode 100644
index 000000000..1b5b377ea
--- /dev/null
+++ b/examples/stm32f7/src/bin/can.rs
@@ -0,0 +1,66 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_stm32::bind_interrupts;
8use embassy_stm32::can::bxcan::filter::Mask32;
9use embassy_stm32::can::bxcan::{Fifo, Frame, StandardId};
10use embassy_stm32::can::{
11 Can, CanTx, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, TxInterruptHandler,
12};
13use embassy_stm32::gpio::{Input, Pull};
14use embassy_stm32::peripherals::CAN3;
15use {defmt_rtt as _, panic_probe as _};
16
17bind_interrupts!(struct Irqs {
18 CAN3_RX0 => Rx0InterruptHandler<CAN3>;
19 CAN3_RX1 => Rx1InterruptHandler<CAN3>;
20 CAN3_SCE => SceInterruptHandler<CAN3>;
21 CAN3_TX => TxInterruptHandler<CAN3>;
22});
23
24#[embassy_executor::task]
25pub async fn send_can_message(tx: &'static mut CanTx<'static, 'static, CAN3>) {
26 loop {
27 let frame = Frame::new_data(unwrap!(StandardId::new(0 as _)), [0]);
28 tx.write(&frame).await;
29 embassy_time::Timer::after(embassy_time::Duration::from_secs(1)).await;
30 }
31}
32
33#[embassy_executor::main]
34async fn main(spawner: Spawner) {
35 info!("Hello World!");
36
37 let mut p = embassy_stm32::init(Default::default());
38
39 // The next two lines are a workaround for testing without transceiver.
40 // To synchronise to the bus the RX input needs to see a high level.
41 // Use `mem::forget()` to release the borrow on the pin but keep the
42 // pull-up resistor enabled.
43 let rx_pin = Input::new(&mut p.PA15, Pull::Up);
44 core::mem::forget(rx_pin);
45
46 let can: &'static mut Can<'static, CAN3> = static_cell::make_static!(Can::new(p.CAN3, p.PA8, p.PA15, Irqs));
47 can.as_mut()
48 .modify_filters()
49 .enable_bank(0, Fifo::Fifo0, Mask32::accept_all());
50
51 can.as_mut()
52 .modify_config()
53 .set_bit_timing(0x001c0001) // http://www.bittiming.can-wiki.info/
54 .set_loopback(true)
55 .enable();
56
57 let (tx, mut rx) = can.split();
58
59 let tx: &'static mut CanTx<'static, 'static, CAN3> = static_cell::make_static!(tx);
60 spawner.spawn(send_can_message(tx)).unwrap();
61
62 loop {
63 let frame = rx.read().await.unwrap();
64 println!("Received: {:?}", frame);
65 }
66}
diff --git a/tests/stm32/src/bin/can.rs b/tests/stm32/src/bin/can.rs
index 33d63d546..8bdd3c24f 100644
--- a/tests/stm32/src/bin/can.rs
+++ b/tests/stm32/src/bin/can.rs
@@ -43,10 +43,13 @@ async fn main(_spawner: Spawner) {
43 43
44 info!("Configuring can..."); 44 info!("Configuring can...");
45 45
46 can.modify_filters().enable_bank(0, Fifo::Fifo0, Mask32::accept_all()); 46 can.as_mut()
47 .modify_filters()
48 .enable_bank(0, Fifo::Fifo0, Mask32::accept_all());
47 49
48 can.set_bitrate(1_000_000); 50 can.set_bitrate(1_000_000);
49 can.modify_config() 51 can.as_mut()
52 .modify_config()
50 .set_loopback(true) // Receive own frames 53 .set_loopback(true) // Receive own frames
51 .set_silent(true) 54 .set_silent(true)
52 // .set_bit_timing(0x001c0003) 55 // .set_bit_timing(0x001c0003)