aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2021-08-18 22:04:56 +0200
committerGitHub <[email protected]>2021-08-18 22:04:56 +0200
commit2b5d1c068fe87fdc119e2a3fab3d4996f7c30f5f (patch)
tree17984bf849141d6b172fa3b4e029505f1115435d
parent0fee2b9509e54e88f31f18df1d0d2b43a86b8a33 (diff)
parentf141b987418ca55500b4f137555a64ea2bbb18d4 (diff)
Merge pull request #352 from timokroeger/can
CAN support with bxcan crate
-rw-r--r--embassy-stm32/Cargo.toml1
-rw-r--r--embassy-stm32/src/can/bxcan.rs144
-rw-r--r--embassy-stm32/src/can/mod.rs5
-rw-r--r--embassy-stm32/src/lib.rs2
-rw-r--r--examples/stm32f4/Cargo.toml1
-rw-r--r--examples/stm32f4/src/bin/can.rs52
6 files changed, 205 insertions, 0 deletions
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml
index fd121f6db..e0c16b46c 100644
--- a/embassy-stm32/Cargo.toml
+++ b/embassy-stm32/Cargo.toml
@@ -26,6 +26,7 @@ bare-metal = "1.0.0"
26atomic-polyfill = "0.1.3" 26atomic-polyfill = "0.1.3"
27stm32-metapac = { version = "0.1.0", path = "../stm32-metapac", features = ["rt"] } 27stm32-metapac = { version = "0.1.0", path = "../stm32-metapac", features = ["rt"] }
28vcell = { version = "0.1.3", optional = true } 28vcell = { version = "0.1.3", optional = true }
29bxcan = { version = "0.5.1" }
29 30
30cfg-if = "1.0.0" 31cfg-if = "1.0.0"
31 32
diff --git a/embassy-stm32/src/can/bxcan.rs b/embassy-stm32/src/can/bxcan.rs
new file mode 100644
index 000000000..906978e8b
--- /dev/null
+++ b/embassy-stm32/src/can/bxcan.rs
@@ -0,0 +1,144 @@
1use core::marker::PhantomData;
2use core::ops::{Deref, DerefMut};
3
4use embassy::util::Unborrow;
5use embassy_hal_common::unborrow;
6
7use crate::gpio::Pin;
8use crate::{peripherals, rcc::RccPeripheral};
9
10pub use bxcan::*;
11
12pub struct Can<'d, T: Instance + bxcan::Instance> {
13 phantom: PhantomData<&'d mut T>,
14 can: bxcan::Can<T>,
15}
16
17impl<'d, T: Instance + bxcan::Instance> Can<'d, T> {
18 pub fn new(
19 peri: impl Unborrow<Target = T> + 'd,
20 rx: impl Unborrow<Target = impl RxPin<T>> + 'd,
21 tx: impl Unborrow<Target = impl TxPin<T>> + 'd,
22 ) -> Self {
23 unborrow!(peri, rx, tx);
24
25 unsafe {
26 rx.set_as_af(rx.af_num());
27 tx.set_as_af(tx.af_num());
28 }
29
30 T::enable();
31 T::reset();
32
33 Self {
34 phantom: PhantomData,
35 can: bxcan::Can::new(peri),
36 }
37 }
38}
39
40impl<'d, T: Instance + bxcan::Instance> Drop for Can<'d, T> {
41 fn drop(&mut self) {
42 // Cannot call `free()` because it moves the instance.
43 // Manually reset the peripheral.
44 unsafe {
45 T::regs().mcr().write(|w| w.set_reset(true));
46 }
47 T::disable();
48 }
49}
50
51impl<'d, T: Instance + bxcan::Instance> Deref for Can<'d, T> {
52 type Target = bxcan::Can<T>;
53
54 fn deref(&self) -> &Self::Target {
55 &self.can
56 }
57}
58
59impl<'d, T: Instance + bxcan::Instance> DerefMut for Can<'d, T> {
60 fn deref_mut(&mut self) -> &mut Self::Target {
61 &mut self.can
62 }
63}
64
65pub(crate) mod sealed {
66 use super::*;
67
68 pub trait Instance {
69 fn regs() -> &'static crate::pac::can::Can;
70 }
71
72 pub trait RxPin<T: Instance>: Pin {
73 fn af_num(&self) -> u8;
74 }
75
76 pub trait TxPin<T: Instance>: Pin {
77 fn af_num(&self) -> u8;
78 }
79}
80
81pub trait Instance: sealed::Instance + RccPeripheral {}
82pub trait RxPin<T: Instance>: sealed::RxPin<T> {}
83pub trait TxPin<T: Instance>: sealed::TxPin<T> {}
84
85crate::pac::peripherals!(
86 (can, $inst:ident) => {
87 impl sealed::Instance for peripherals::$inst {
88 fn regs() -> &'static crate::pac::can::Can {
89 &crate::pac::$inst
90 }
91 }
92
93 impl Instance for peripherals::$inst {}
94
95 unsafe impl bxcan::Instance for peripherals::$inst {
96 const REGISTERS: *mut bxcan::RegisterBlock = crate::pac::$inst.0 as *mut _;
97 }
98 };
99);
100
101crate::pac::peripherals!(
102 (can, CAN) => {
103 unsafe impl bxcan::FilterOwner for peripherals::$inst {
104 const NUM_FILTER_BANKS: u8 = 14;
105 }
106 };
107 // Only correct when CAN2 also exists… Fix on yaml level?
108 // There are only 14 filter banks when CAN2 is not available.
109 (can, CAN1) => {
110 unsafe impl bxcan::FilterOwner for peripherals::CAN1 {
111 const NUM_FILTER_BANKS: u8 = 28;
112 }
113 };
114 (can, CAN2) => {
115 // CAN2 is always a slave instance where CAN1 is the master instance
116 unsafe impl bxcan::MasterInstance for peripherals::CAN1 {}
117 };
118 (can, CAN3) => {
119 unsafe impl bxcan::FilterOwner for peripherals::$inst {
120 const NUM_FILTER_BANKS: u8 = 14;
121 }
122 };
123);
124
125macro_rules! impl_pin {
126 ($inst:ident, $pin:ident, $signal:ident, $af:expr) => {
127 impl $signal<peripherals::$inst> for peripherals::$pin {}
128
129 impl sealed::$signal<peripherals::$inst> for peripherals::$pin {
130 fn af_num(&self) -> u8 {
131 $af
132 }
133 }
134 };
135}
136
137crate::pac::peripheral_pins!(
138 ($inst:ident, can, CAN, $pin:ident, TX, $af:expr) => {
139 impl_pin!($inst, $pin, TxPin, $af);
140 };
141 ($inst:ident, can, CAN, $pin:ident, RX, $af:expr) => {
142 impl_pin!($inst, $pin, RxPin, $af);
143 };
144);
diff --git a/embassy-stm32/src/can/mod.rs b/embassy-stm32/src/can/mod.rs
new file mode 100644
index 000000000..c7e2e620a
--- /dev/null
+++ b/embassy-stm32/src/can/mod.rs
@@ -0,0 +1,5 @@
1#![macro_use]
2
3#[cfg_attr(can_bxcan, path = "bxcan.rs")]
4mod _version;
5pub use _version::*;
diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs
index 8a213b680..af4ab95fd 100644
--- a/embassy-stm32/src/lib.rs
+++ b/embassy-stm32/src/lib.rs
@@ -27,6 +27,8 @@ mod time_driver;
27 27
28#[cfg(adc)] 28#[cfg(adc)]
29pub mod adc; 29pub mod adc;
30#[cfg(can)]
31pub mod can;
30#[cfg(dac)] 32#[cfg(dac)]
31pub mod dac; 33pub mod dac;
32#[cfg(dbgmcu)] 34#[cfg(dbgmcu)]
diff --git a/examples/stm32f4/Cargo.toml b/examples/stm32f4/Cargo.toml
index c254573f8..95c8441d9 100644
--- a/examples/stm32f4/Cargo.toml
+++ b/examples/stm32f4/Cargo.toml
@@ -32,3 +32,4 @@ panic-probe = { version = "0.2.0", features= ["print-defmt"] }
32futures = { version = "0.3.8", default-features = false, features = ["async-await"] } 32futures = { version = "0.3.8", default-features = false, features = ["async-await"] }
33rtt-target = { version = "0.3", features = ["cortex-m"] } 33rtt-target = { version = "0.3", features = ["cortex-m"] }
34heapless = { version = "0.7.1", default-features = false } 34heapless = { version = "0.7.1", default-features = false }
35nb = { version = "1.0" }
diff --git a/examples/stm32f4/src/bin/can.rs b/examples/stm32f4/src/bin/can.rs
new file mode 100644
index 000000000..2bb24f045
--- /dev/null
+++ b/examples/stm32f4/src/bin/can.rs
@@ -0,0 +1,52 @@
1#![no_std]
2#![no_main]
3#![feature(trait_alias)]
4#![feature(type_alias_impl_trait)]
5#![allow(incomplete_features)]
6
7#[path = "../example_common.rs"]
8mod example_common;
9
10use cortex_m_rt::entry;
11use embassy_stm32::can::filter::Mask32;
12use embassy_stm32::can::{Can, Frame, StandardId};
13use embassy_stm32::dbgmcu::Dbgmcu;
14use embassy_stm32::gpio::{Input, Pull};
15use example_common::*;
16
17#[entry]
18fn main() -> ! {
19 info!("Hello World!");
20
21 unsafe {
22 Dbgmcu::enable_all();
23 }
24
25 let mut p = embassy_stm32::init(Default::default());
26
27 // The next two lines are a workaround for testing without transceiver.
28 // To synchronise to the bus the RX input needs to see a high level.
29 // Use `mem::forget()` to release the borrow on the pin but keep the
30 // pull-up resistor enabled.
31 let rx_pin = Input::new(&mut p.PA11, Pull::Up);
32 core::mem::forget(rx_pin);
33
34 let mut can = Can::new(p.CAN1, p.PA11, p.PA12);
35
36 can.modify_config()
37 .set_bit_timing(0x001c0003) // http://www.bittiming.can-wiki.info/
38 .set_loopback(true) // Receive own frames
39 .set_silent(true);
40 can.modify_filters().enable_bank(0, Mask32::accept_all());
41 unwrap!(nb::block!(can.enable()));
42
43 let mut i: u8 = 0;
44 loop {
45 let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), [i]);
46 unwrap!(nb::block!(can.transmit(&tx_frame)));
47 while !can.is_transmitter_idle() {}
48 let rx_frame = unwrap!(nb::block!(can.receive()));
49 info!("loopback frame {=u8}", unwrap!(rx_frame.data())[0]);
50 i += 1;
51 }
52}