Skip to content

Commit e9c9965

Browse files
Merge #128
128: bxcan-based CAN interface r=therealprof a=jonas-schievink This changes the CAN API to use the [bxcan](https://github.com/jonas-schievink/bxcan) crate, a reusable driver for the bxCAN peripherals in many low- to middle-end STM32 MCUs. Co-authored-by: Jonas Schievink <[email protected]>
2 parents fba9834 + 27e959e commit e9c9965

File tree

3 files changed

+47
-183
lines changed

3 files changed

+47
-183
lines changed

CHANGELOG.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
77

88
## [Unreleased]
99

10-
- Add CAN bus abstraction.
10+
- Add CAN bus abstraction based on the [bxcan] crate.
11+
12+
[bxcan]: https://crates.io/crates/bxcan
1113

1214
## [v0.17.1] - 2020-08-30
1315

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ stm32f0 = "0.12.1"
3838
nb = "1.0"
3939
void = { version = "1.0", default-features = false }
4040
stm32-usbd = { version = "0.5.1", features = ["ram_access_2x16"], optional = true }
41+
bxcan = "0.4.0"
4142

4243
[dev-dependencies]
4344
cortex-m-rt = "0.6"

src/can.rs

Lines changed: 43 additions & 182 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,33 @@
1-
use super::pac;
2-
use super::pac::can::TX;
1+
use bxcan::{FilterOwner, Instance, RegisterBlock};
2+
33
use crate::gpio::gpioa::{PA11, PA12};
44
use crate::gpio::gpiob::{PB8, PB9};
55
use crate::gpio::{Alternate, AF4};
6+
use crate::pac::CAN;
67
use crate::rcc::Rcc;
78

8-
pub trait RxPin {}
9-
pub trait TxPin {}
9+
mod sealed {
10+
pub trait Sealed {}
11+
}
12+
13+
use self::sealed::Sealed;
14+
15+
pub use bxcan;
16+
17+
pub trait RxPin: Sealed {}
18+
pub trait TxPin: Sealed {}
1019

1120
macro_rules! can_pins {
1221
(
1322
rx => [$($rx:ty),+ $(,)*],
1423
tx => [$($tx:ty),+ $(,)*],
1524
) => {
1625
$(
26+
impl Sealed for $rx {}
1727
impl RxPin for $rx {}
1828
)+
1929
$(
30+
impl Sealed for $tx {}
2031
impl TxPin for $tx {}
2132
)+
2233
};
@@ -28,198 +39,48 @@ can_pins! {
2839
tx => [PA12<Alternate<AF4>>, PB9<Alternate<AF4>>],
2940
}
3041

31-
pub struct CANBus<RX_PIN, TX_PIN> {
32-
can: pac::CAN,
33-
_rx: RX_PIN,
34-
_tx: TX_PIN,
42+
#[cfg(any(feature = "stm32f072", feature = "stm32f091"))]
43+
use crate::gpio::{
44+
gpiod::{PD0, PD1},
45+
AF0,
46+
};
47+
48+
#[cfg(any(feature = "stm32f072", feature = "stm32f091"))]
49+
can_pins! {
50+
rx => [PD0<Alternate<AF0>>],
51+
tx => [PD1<Alternate<AF0>>],
3552
}
3653

37-
pub enum Event {
38-
RxMessagePending,
54+
/// Resources used by the CAN peripheral.
55+
pub struct CanInstance<T: TxPin, R: RxPin> {
56+
peripheral: CAN,
57+
tx: T,
58+
rx: R,
3959
}
4060

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 {
61+
impl<T: TxPin, R: RxPin> CanInstance<T, R> {
62+
pub fn new(peripheral: CAN, tx: T, rx: R, rcc: &mut Rcc) -> Self {
4763
rcc.regs.apb1enr.modify(|_, w| w.canen().enabled());
4864
rcc.regs.apb1rstr.modify(|_, w| w.canrst().reset());
4965
rcc.regs.apb1rstr.modify(|_, w| w.canrst().clear_bit());
5066

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-
}
67+
Self { peripheral, tx, rx }
13068
}
13169

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-
});
70+
pub fn into_raw(self) -> (CAN, T, R) {
71+
(self.peripheral, self.tx, self.rx)
16572
}
16673

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-
}
74+
/// Returns a reference to the raw CAN peripheral.
75+
pub unsafe fn peripheral(&mut self) -> &mut CAN {
76+
&mut self.peripheral
21477
}
21578
}
21679

217-
pub enum CANError {}
80+
unsafe impl<T: TxPin, R: RxPin> Instance for CanInstance<T, R> {
81+
const REGISTERS: *mut RegisterBlock = CAN::ptr() as *mut _;
82+
}
21883

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],
84+
unsafe impl<T: TxPin, R: RxPin> FilterOwner for CanInstance<T, R> {
85+
const NUM_FILTER_BANKS: u8 = 14;
22586
}

0 commit comments

Comments
 (0)