Skip to content

Commit 9e29ec6

Browse files
authored
Merge pull request #186 from zklapow/can-fix-patch
Small fixes for CAN
2 parents 1053b01 + 30ac7f2 commit 9e29ec6

File tree

2 files changed

+101
-30
lines changed

2 files changed

+101
-30
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
77

88
## [Unreleased]
99

10+
### Changed
11+
12+
- Added support for more CAN bit rates and modes. ([#186](https://github.com/stm32-rs/stm32f3xx-hal/pull/186)
13+
1014
## [v0.6.1] - 2020-12-10
1115

1216
### Changed

src/can.rs

Lines changed: 97 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,72 @@ use crate::stm32;
2020
use nb::{self, Error};
2121

2222
use core::sync::atomic::{AtomicU8, Ordering};
23+
pub use stm32::can::btr::LBKM_A;
2324

2425
const EXID_MASK: u32 = 0b1_1111_1111_1100_0000_0000_0000_0000;
2526
const MAX_EXTENDED_ID: u32 = 0x1FFF_FFFF;
2627

28+
/// Options the CAN bus. This is primarily used to set bus timings, but also controls options like enabling loopback or silent mode for debugging.
29+
/// See http://www.bittiming.can-wiki.info/#bxCAN for generating the timing parameters for different baud rates and clocks.
30+
///
31+
/// Use `CanOpts::default()` to get 250kbps at 32mhz system clock
32+
pub struct CanOpts {
33+
brp: u16,
34+
sjw: u8,
35+
ts1: u8,
36+
ts2: u8,
37+
lbkm: LBKM_A,
38+
}
39+
40+
impl CanOpts {
41+
/// Create new `CanOpts` using the default settings from `CanOpts::default()` to get 250kbps at 32mhz system clock.
42+
pub fn new() -> CanOpts {
43+
CanOpts::default()
44+
}
45+
46+
/// Set the Baud Rate Prescaler. See http://www.bittiming.can-wiki.info/#bxCAN for generating the timing parameters for different baud rates and clocks.
47+
pub fn brp(mut self, brp: u16) -> Self {
48+
self.brp = brp;
49+
self
50+
}
51+
52+
/// Set the Resynchronisation Jump Width. See http://www.bittiming.can-wiki.info/#bxCAN for generating the timing parameters for different baud rates and clocks.
53+
pub fn sjw(mut self, sjw: u8) -> Self {
54+
self.sjw = sjw;
55+
self
56+
}
57+
58+
/// Set Time Segment One. See http://www.bittiming.can-wiki.info/#bxCAN for generating the timing parameters for different baud rates and clocks.
59+
pub fn ts1(mut self, ts1: u8) -> Self {
60+
self.ts1 = ts1;
61+
self
62+
}
63+
64+
/// Set Time Segment Two. See http://www.bittiming.can-wiki.info/#bxCAN for generating the timing parameters for different baud rates and clocks.
65+
pub fn ts2(mut self, ts2: u8) -> Self {
66+
self.ts2 = ts2;
67+
self
68+
}
69+
70+
/// Enable or disable loopback mode on the CAN device. This is useful for debugging.
71+
pub fn lbkm(mut self, lbkm: LBKM_A) -> Self {
72+
self.lbkm = lbkm;
73+
self
74+
}
75+
}
76+
77+
impl Default for CanOpts {
78+
fn default() -> Self {
79+
CanOpts {
80+
brp: 4,
81+
sjw: 0,
82+
ts1: 10,
83+
ts2: 3,
84+
lbkm: LBKM_A::DISABLED,
85+
}
86+
}
87+
}
88+
2789
/// A CAN identifier, which can be either 11 or 27 (extended) bits.
2890
/// u16 and u32 respectively are used here despite the fact that the upper bits are unused.
2991
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
@@ -252,42 +314,28 @@ impl CanFilterData {
252314
}
253315

254316
impl Can {
255-
/// Initialize the CAN Peripheral
256-
pub fn new(
317+
/// Initialize the CAN peripheral using the options specified by `opts`.
318+
pub fn new_with_opts(
257319
can: stm32::CAN,
258320
rx: gpioa::PA11<AF9>,
259321
tx: gpioa::PA12<AF9>,
260322
apb1: &mut APB1,
261-
) -> Self {
323+
opts: CanOpts,
324+
) -> Can {
262325
apb1.enr().modify(|_, w| w.canen().enabled());
263326
can.mcr.modify(|_, w| w.sleep().clear_bit());
264327
can.mcr.modify(|_, w| w.inrq().set_bit());
265328

266329
// Wait for INAK to confirm we have entered initialization mode
267330
while !can.msr.read().inak().bit_is_set() {}
268331

269-
// TODO: actually calculate baud params
270-
271-
// Our baud rate calc here is aiming for roughly 4000uS total bit time or about 250kbps
272-
// Though we actually allow closer to 5500uS total given the sjw setting
273-
// Calculations for timing value from http://www.bittiming.can-wiki.info/#bxCAN
274-
275-
// Baud rate prescaler defines time quanta
276-
// tq = (BRP[9:0]+1) x tPCLK
277-
let brp: u16 = 4;
278-
279-
// Resynchronization jump width: number of quanta segments may be expanded to resync
280-
// tRJW = tq x (SJW[1:0] + 1)
281-
let sjw = 0;
282-
283-
// Time seg 2
284-
// tBS2 = tq x (TS2[2:0] + 1)
285-
let ts2 = 3;
286-
287-
// Time seg 1
288-
// tBS1 = tq x (TS1[3:0] + 1)
289-
let ts1 = 10;
290-
332+
let CanOpts {
333+
brp,
334+
sjw,
335+
ts1,
336+
ts2,
337+
lbkm,
338+
} = opts;
291339
can.btr.modify(|_, w| unsafe {
292340
w.brp()
293341
.bits(brp)
@@ -297,8 +345,8 @@ impl Can {
297345
.bits(ts1)
298346
.ts2()
299347
.bits(ts2)
300-
//.lbkm()
301-
//.set_bit()
348+
.lbkm()
349+
.variant(lbkm)
302350
});
303351

304352
// Leave initialization mode by clearing INRQ and switch to normal mode
@@ -312,6 +360,15 @@ impl Can {
312360
_tx: tx,
313361
}
314362
}
363+
/// Initialize the CAN Peripheral using default options from `CanOpts::default()`
364+
pub fn new(
365+
can: stm32::CAN,
366+
rx: gpioa::PA11<AF9>,
367+
tx: gpioa::PA12<AF9>,
368+
apb1: &mut APB1,
369+
) -> Self {
370+
Can::new_with_opts(can, rx, tx, apb1, CanOpts::default())
371+
}
315372

316373
/// Enable CAN event interrupts for `Event`
317374
pub fn listen(&mut self, event: Event) {
@@ -407,7 +464,7 @@ impl embedded_hal_can::Transmitter for CanTransmitter {
407464

408465
// NOTE(unsafe): full 8bit write is unsafe via the svd2rust api
409466
tx.tdtr
410-
.modify(|_, w| unsafe { w.dlc().bits(data.len() as u8) });
467+
.modify(|_, w| unsafe { w.dlc().bits(frame.dlc as u8) });
411468

412469
tx.tir.modify(|_, w| w.rtr().clear_bit());
413470
} else {
@@ -554,7 +611,7 @@ impl CanFrame {
554611
///
555612
/// This function will panic if length of `data` is greater than `8`
556613
pub fn new_data(id: CanId, data: &[u8]) -> CanFrame {
557-
crate::assert!((0..8).contains(&data.len()));
614+
crate::assert!((0..=8).contains(&data.len()));
558615

559616
let mut frame = Self {
560617
id,
@@ -569,7 +626,7 @@ impl CanFrame {
569626
///
570627
/// # Panics
571628
///
572-
/// This function will panic if `dlc` is not inside the vliad range `0..=8`.
629+
/// This function will panic if `dlc` is not inside the valid range `0..=8`.
573630
pub fn new_remote(id: CanId, dlc: usize) -> CanFrame {
574631
assert!((0..=8).contains(&dlc));
575632

@@ -579,4 +636,14 @@ impl CanFrame {
579636
data: [0; 8],
580637
}
581638
}
639+
640+
/// Length of the frame data
641+
pub fn len(&self) -> usize {
642+
self.dlc
643+
}
644+
645+
/// Is this frame empty. This usually indicates a remote frame.
646+
pub fn is_empty(&self) -> bool {
647+
self.dlc == 0
648+
}
582649
}

0 commit comments

Comments
 (0)