Skip to content

Commit a7daf77

Browse files
Merge #125
125: Add CAN bus. r=therealprof a=matoushybl Adds CAN bus as I developed it for my project. Any feedback is welcome. I'll continue the development to make it fully working in context of the HAL. Also CAN traits are under review in embedded-hal, so I might implement the traits before they are merged for future compatibility. Co-authored-by: Matous Hybl <[email protected]>
2 parents de9f121 + 788f222 commit a7daf77

File tree

3 files changed

+233
-0
lines changed

3 files changed

+233
-0
lines changed

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
77

88
## [Unreleased]
99

10+
- Add CAN bus abstraction.
11+
1012
## [v0.17.1] - 2020-08-30
1113

1214
### Changed

src/can.rs

+225
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
use super::pac;
2+
use super::pac::can::TX;
3+
use crate::gpio::gpioa::{PA11, PA12};
4+
use crate::gpio::gpiob::{PB8, PB9};
5+
use crate::gpio::{Alternate, AF4};
6+
use crate::rcc::Rcc;
7+
8+
pub trait RxPin {}
9+
pub trait TxPin {}
10+
11+
macro_rules! can_pins {
12+
(
13+
rx => [$($rx:ty),+ $(,)*],
14+
tx => [$($tx:ty),+ $(,)*],
15+
) => {
16+
$(
17+
impl RxPin for $rx {}
18+
)+
19+
$(
20+
impl TxPin for $tx {}
21+
)+
22+
};
23+
}
24+
25+
#[cfg(any(feature = "stm32f042", feature = "stm32f072", feature = "stm32f091"))]
26+
can_pins! {
27+
rx => [PA11<Alternate<AF4>>, PB8<Alternate<AF4>>],
28+
tx => [PA12<Alternate<AF4>>, PB9<Alternate<AF4>>],
29+
}
30+
31+
pub struct CANBus<RX_PIN, TX_PIN> {
32+
can: pac::CAN,
33+
_rx: RX_PIN,
34+
_tx: TX_PIN,
35+
}
36+
37+
pub enum Event {
38+
RxMessagePending,
39+
}
40+
41+
impl<RX_PIN, TX_PIN> CANBus<RX_PIN, TX_PIN>
42+
where
43+
RX_PIN: RxPin,
44+
TX_PIN: TxPin,
45+
{
46+
pub fn new(can: pac::CAN, rx: RX_PIN, tx: TX_PIN, rcc: &mut Rcc) -> Self {
47+
rcc.regs.apb1enr.modify(|_, w| w.canen().enabled());
48+
rcc.regs.apb1rstr.modify(|_, w| w.canrst().reset());
49+
rcc.regs.apb1rstr.modify(|_, w| w.canrst().clear_bit());
50+
51+
can.mcr.write(|w| w.sleep().clear_bit());
52+
can.mcr.modify(|_, w| w.inrq().set_bit());
53+
while !can.msr.read().inak().bit() {}
54+
55+
can.mcr.modify(|_, w| {
56+
w.ttcm()
57+
.clear_bit() // no time triggered communication
58+
.abom()
59+
.set_bit() // bus automatically recovers itself after error state
60+
.awum()
61+
.set_bit() // bus is automatically waken up on message RX
62+
.nart()
63+
.clear_bit() // automatic message retransmission enabled
64+
.rflm()
65+
.clear_bit() // new RX message overwrite unread older ones
66+
.txfp()
67+
.clear_bit() // TX message priority driven by the message identifier
68+
.sleep()
69+
.clear_bit() // do not sleep
70+
});
71+
// calculated using http://www.bittiming.can-wiki.info/ for STMicroelectronics bxCAN 48 MHz clock, 87.6% sample point, SJW = 1, bitrate 250 kHz
72+
const TIME_SEGMENT1: u8 = 13;
73+
const TIME_SEGMENT2: u8 = 2;
74+
const RESYNC_WIDTH: u8 = 1;
75+
const PRESCALER: u16 = 12;
76+
can.btr.modify(|_, w| unsafe {
77+
w.silm()
78+
.clear_bit() // disable silent mode
79+
.lbkm()
80+
.clear_bit() // disable loopback mode
81+
.sjw()
82+
.bits(RESYNC_WIDTH - 1)
83+
.ts2()
84+
.bits(TIME_SEGMENT2 - 1)
85+
.ts1()
86+
.bits(TIME_SEGMENT1 - 1)
87+
.brp()
88+
.bits(PRESCALER - 1)
89+
});
90+
91+
can.mcr.modify(|_, w| w.inrq().clear_bit());
92+
while !can.msr.read().inak().bit() {}
93+
94+
can.fmr.modify(|_, w| w.finit().set_bit()); // filter init enabled
95+
can.fa1r.write(|w| w.fact0().clear_bit()); // filter is inactive
96+
97+
can.fm1r.write(|w| w.fbm0().clear_bit()); // identifier mask mode for fbm0
98+
can.fs1r.write(|w| w.fsc0().set_bit()); // 32 bit scale configuration
99+
100+
// const FILTER0_ID: u16 = 0x0;
101+
// const FILTER0_MASK: u16 = 0x00;
102+
// const FILTER1_ID: u16 = 0x00;
103+
// const FILTER1_MASK: u16 = 0x00;
104+
can.fb[0].fr1.write(|w| unsafe { w.bits(0) });
105+
can.fb[0].fr2.write(|w| unsafe { w.bits(0) });
106+
107+
can.fa1r.write(|w| w.fact0().set_bit()); // filter is active
108+
can.fmr.modify(|_, w| w.finit().clear_bit()); // filter init disabled
109+
110+
Self {
111+
can,
112+
_rx: rx,
113+
_tx: tx,
114+
}
115+
}
116+
117+
pub fn write(&self, frame: &CANFrame) -> nb::Result<(), CANError> {
118+
if self.can.tsr.read().tme0().bit_is_set() {
119+
self.write_to_mailbox(&self.can.tx[0], frame);
120+
Ok(())
121+
} else if self.can.tsr.read().tme1().bit_is_set() {
122+
self.write_to_mailbox(&self.can.tx[1], frame);
123+
Ok(())
124+
} else if self.can.tsr.read().tme2().bit_is_set() {
125+
self.write_to_mailbox(&self.can.tx[2], frame);
126+
Ok(())
127+
} else {
128+
Err(nb::Error::WouldBlock)
129+
}
130+
}
131+
132+
fn write_to_mailbox(&self, tx: &TX, frame: &CANFrame) {
133+
tx.tdtr.write(|w| unsafe { w.dlc().bits(frame.dlc) });
134+
tx.tdlr.write(|w| unsafe {
135+
w.data0()
136+
.bits(frame.data[0])
137+
.data1()
138+
.bits(frame.data[1])
139+
.data2()
140+
.bits(frame.data[2])
141+
.data3()
142+
.bits(frame.data[3])
143+
});
144+
tx.tdhr.write(|w| unsafe {
145+
w.data4()
146+
.bits(frame.data[4])
147+
.data5()
148+
.bits(frame.data[5])
149+
.data6()
150+
.bits(frame.data[6])
151+
.data7()
152+
.bits(frame.data[7])
153+
});
154+
155+
tx.tir.write(|w| unsafe {
156+
w.stid()
157+
.bits(frame.id)
158+
.ide()
159+
.standard()
160+
.rtr()
161+
.bit(frame.rtr)
162+
.txrq()
163+
.set_bit()
164+
});
165+
}
166+
167+
pub fn read(&self) -> nb::Result<CANFrame, CANError> {
168+
for (i, rfr) in self.can.rfr.iter().enumerate() {
169+
let pending = rfr.read().fmp().bits();
170+
if pending > 0 {
171+
let rx = &self.can.rx[i];
172+
let id = rx.rir.read().stid().bits();
173+
let rtr = rx.rir.read().rtr().bit_is_set();
174+
let dlc = rx.rdtr.read().dlc().bits();
175+
176+
let data0 = rx.rdlr.read().data0().bits();
177+
let data1 = rx.rdlr.read().data1().bits();
178+
let data2 = rx.rdlr.read().data2().bits();
179+
let data3 = rx.rdlr.read().data3().bits();
180+
let data4 = rx.rdhr.read().data4().bits();
181+
let data5 = rx.rdhr.read().data5().bits();
182+
let data6 = rx.rdhr.read().data6().bits();
183+
let data7 = rx.rdhr.read().data7().bits();
184+
185+
rfr.modify(|_, w| w.rfom().release()); // release
186+
if rfr.read().fovr().bit_is_set() {
187+
rfr.modify(|_, w| w.fovr().clear());
188+
}
189+
190+
if rfr.read().full().bit_is_set() {
191+
rfr.modify(|_, w| w.full().clear());
192+
}
193+
194+
let frame = CANFrame {
195+
id,
196+
rtr,
197+
dlc,
198+
data: [data0, data1, data2, data3, data4, data5, data6, data7],
199+
};
200+
return Ok(frame);
201+
}
202+
}
203+
Err(nb::Error::WouldBlock)
204+
}
205+
206+
pub fn listen(&self, event: Event) {
207+
match event {
208+
Event::RxMessagePending => {
209+
self.can
210+
.ier
211+
.modify(|_, w| w.fmpie0().set_bit().fmpie1().set_bit());
212+
}
213+
}
214+
}
215+
}
216+
217+
pub enum CANError {}
218+
219+
#[derive(Copy, Clone, Default)]
220+
pub struct CANFrame {
221+
pub id: u16,
222+
pub rtr: bool,
223+
pub dlc: u8,
224+
pub data: [u8; 8],
225+
}

src/lib.rs

+6
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,12 @@ pub mod usb;
8484
#[cfg(feature = "device-selected")]
8585
pub mod watchdog;
8686

87+
#[cfg(all(
88+
feature = "device-selected",
89+
any(feature = "stm32f091", feature = "stm32f042", feature = "stm32f072",)
90+
))]
91+
pub mod can;
92+
8793
#[cfg(feature = "device-selected")]
8894
#[deprecated(since = "0.17.0", note = "please use `pac` instead")]
8995
pub use pac as stm32;

0 commit comments

Comments
 (0)