Skip to content

Commit 280ab07

Browse files
committed
[WIP] Add CANBus.
1 parent c7f710e commit 280ab07

File tree

2 files changed

+206
-0
lines changed

2 files changed

+206
-0
lines changed

src/can.rs

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

src/lib.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,12 @@ pub mod usb;
8686
#[cfg(feature = "device-selected")]
8787
pub mod watchdog;
8888

89+
// TODO other controllers have CAN
90+
#[cfg(any(
91+
feature = "stm32f091",
92+
))]
93+
pub mod can;
94+
8995
#[cfg(feature = "device-selected")]
9096
#[deprecated(since = "0.17.0", note = "please use `pac` instead")]
9197
pub use pac as stm32;

0 commit comments

Comments
 (0)