forked from stm32-rs/stm32f1xx-hal
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcan-loopback.rs
118 lines (97 loc) · 3.63 KB
/
can-loopback.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
//! Showcases advanced CAN filter capabilities.
//! Does not require additional transceiver hardware.
#![no_main]
#![no_std]
use bxcan::{
filter::{ListEntry16, ListEntry32, Mask16},
ExtendedId, Fifo, Frame, StandardId,
};
use panic_halt as _;
use cortex_m_rt::entry;
use nb::block;
use stm32f1xx_hal::{can::Can, pac, prelude::*};
#[entry]
fn main() -> ! {
let dp = pac::Peripherals::take().unwrap();
let mut flash = dp.FLASH.constrain();
let rcc = dp.RCC.constrain();
// To meet CAN clock accuracy requirements, an external crystal or ceramic
// resonator must be used.
rcc.cfgr.use_hse(8.MHz()).freeze(&mut flash.acr);
#[cfg(not(feature = "connectivity"))]
let can = Can::new(dp.CAN1, dp.USB);
#[cfg(feature = "connectivity")]
let can = Can::new(dp.CAN1);
// Use loopback mode: No pins need to be assigned to peripheral.
// APB1 (PCLK1): 8MHz, Bit rate: 500Bit/s, Sample Point 87.5%
// Value was calculated with http://www.bittiming.can-wiki.info/
let mut can = bxcan::Can::builder(can)
.set_bit_timing(0x001c_0000)
.set_loopback(true)
.set_silent(true)
.leave_disabled();
let mut filters = can.modify_filters();
assert!(filters.num_banks() > 3);
// The order of the added filters is important: it must match configuration
// of the `split_filters_advanced()` method.
// 2x 11bit id + mask filter bank: Matches 0, 1, 2
// TODO: Make this accept also ID 2
filters.enable_bank(
0,
Fifo::Fifo0,
[
// accepts 0 and 1
Mask16::frames_with_std_id(StandardId::new(0).unwrap(), StandardId::new(1).unwrap()),
// accepts 0 and 2
Mask16::frames_with_std_id(StandardId::new(0).unwrap(), StandardId::new(2).unwrap()),
],
);
// 2x 29bit id filter bank: Matches 4, 5
filters.enable_bank(
1,
Fifo::Fifo0,
[
ListEntry32::data_frames_with_id(ExtendedId::new(4).unwrap()),
ListEntry32::data_frames_with_id(ExtendedId::new(5).unwrap()),
],
);
// 4x 11bit id filter bank: Matches 8, 9, 10, 11
filters.enable_bank(
2,
Fifo::Fifo0,
[
ListEntry16::data_frames_with_id(StandardId::new(8).unwrap()),
ListEntry16::data_frames_with_id(StandardId::new(9).unwrap()),
ListEntry16::data_frames_with_id(StandardId::new(10).unwrap()),
ListEntry16::data_frames_with_id(StandardId::new(11).unwrap()),
],
);
// Enable filters.
drop(filters);
// Sync to the bus and start normal operation.
block!(can.enable_non_blocking()).ok();
// Some messages shall pass the filters.
for &id in &[0, 1, 2, 8, 9, 10, 11] {
let frame_tx = Frame::new_data(StandardId::new(id).unwrap(), [id as u8]);
block!(can.transmit(&frame_tx)).unwrap();
let frame_rx = block!(can.receive()).unwrap();
assert_eq!(frame_tx, frame_rx);
}
for &id in &[4, 5] {
let frame_tx = Frame::new_data(ExtendedId::new(id).unwrap(), [id as u8]);
block!(can.transmit(&frame_tx)).unwrap();
let frame_rx = block!(can.receive()).unwrap();
assert_eq!(frame_tx, frame_rx);
}
// Some messages shall not be received.
for &id in &[3, 6, 7, 12] {
let frame_tx = Frame::new_data(ExtendedId::new(id).unwrap(), [id as u8]);
block!(can.transmit(&frame_tx)).unwrap();
while !can.is_transmitter_idle() {}
assert!(can.receive().is_err());
}
let mut gpiob = dp.GPIOB.split();
let mut led = gpiob.pb9.into_push_pull_output(&mut gpiob.crh);
led.set_high();
loop {}
}