Skip to content

Commit e5327cd

Browse files
authored
Merge pull request #224 from stm32-rs/bxcan
bxCAN impl
2 parents 158315f + 21f60ce commit e5327cd

File tree

4 files changed

+208
-0
lines changed

4 files changed

+208
-0
lines changed

Cargo.toml

+5
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ edition = "2018"
2424
cortex-m = "0.6.3"
2525
nb = "0.1.1"
2626
stm32l4 = "0.13.0"
27+
bxcan = "0.5"
2728

2829
[dependencies.rand_core]
2930
version = "0.6.2"
@@ -99,6 +100,10 @@ lto = true
99100
name = "adc"
100101
required-features = ["rt", "stm32l4x3"]
101102

103+
[[example]]
104+
name = "can-loopback"
105+
required-features = ["rt", "stm32l4x1"]
106+
102107
[[example]]
103108
name = "irq_button"
104109
required-features = ["rt"]

examples/can-loopback.rs

+94
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
//! Run the bxCAN peripheral in loopback mode.
2+
3+
#![deny(unsafe_code)]
4+
#![deny(warnings)]
5+
#![no_main]
6+
#![no_std]
7+
8+
use bxcan::{
9+
filter::Mask32,
10+
{Frame, StandardId},
11+
};
12+
use panic_halt as _;
13+
use rtic::app;
14+
use rtt_target::{rprintln, rtt_init_print};
15+
use stm32l4xx_hal::{can::Can, prelude::*};
16+
17+
#[app(device = stm32l4xx_hal::stm32, peripherals = true)]
18+
const APP: () = {
19+
#[init]
20+
fn init(cx: init::Context) {
21+
rtt_init_print!();
22+
23+
let dp = cx.device;
24+
25+
let mut flash = dp.FLASH.constrain();
26+
let mut rcc = dp.RCC.constrain();
27+
let mut pwr = dp.PWR.constrain(&mut rcc.apb1r1);
28+
let mut gpioa = dp.GPIOA.split(&mut rcc.ahb2);
29+
30+
// Set the clocks to 80 MHz
31+
let _clocks = rcc.cfgr.sysclk(80.mhz()).freeze(&mut flash.acr, &mut pwr);
32+
33+
rprintln!(" - CAN init");
34+
35+
let mut can = {
36+
let rx = gpioa.pa11.into_af9(&mut gpioa.moder, &mut gpioa.afrh);
37+
let tx = gpioa.pa12.into_af9(&mut gpioa.moder, &mut gpioa.afrh);
38+
39+
let can = Can::new(&mut rcc.apb1r1, dp.CAN1, (tx, rx));
40+
41+
bxcan::Can::new(can)
42+
};
43+
can.configure(|config| {
44+
// APB1 (PCLK1): 80 MHz, Bit rate: 100kBit/s, Sample Point 87.5%
45+
// Value was calculated with http://www.bittiming.can-wiki.info/
46+
config.set_bit_timing(0x001c_0031);
47+
config.set_loopback(true);
48+
});
49+
50+
// Configure filters so that can frames can be received.
51+
let mut filters = can.modify_filters();
52+
filters.enable_bank(0, Mask32::accept_all());
53+
54+
// Drop filters to leave filter configuraiton mode.
55+
drop(filters);
56+
57+
// Enable and wait for bxCAN sync to bus
58+
while let Err(_) = can.enable() {}
59+
60+
// Send a frame
61+
let mut test: [u8; 8] = [0; 8];
62+
let id: u16 = 0x500;
63+
64+
test[0] = 72;
65+
test[1] = 1;
66+
test[2] = 2;
67+
test[3] = 3;
68+
test[4] = 4;
69+
test[5] = 5;
70+
test[6] = 6;
71+
test[7] = 7;
72+
let test_frame = Frame::new_data(StandardId::new(id).unwrap(), test);
73+
can.transmit(&test_frame).unwrap();
74+
75+
// Wait for TX to finish
76+
while !can.is_transmitter_idle() {}
77+
78+
rprintln!(" - CAN tx complete: {:?}", test_frame);
79+
80+
// Receive the packet back
81+
let r = can.receive();
82+
83+
rprintln!(" - CAN rx {:?}", r);
84+
85+
assert_eq!(Ok(test_frame), r);
86+
}
87+
88+
#[idle]
89+
fn idle(_: idle::Context) -> ! {
90+
loop {
91+
continue;
92+
}
93+
}
94+
};

src/can.rs

+107
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
//! # Controller Area Network (CAN) Interface
2+
//!
3+
//! Based on STM32F4xx HAL.
4+
5+
use crate::pac::CAN1;
6+
use crate::rcc::APB1R1;
7+
8+
mod sealed {
9+
pub trait Sealed {}
10+
}
11+
12+
/// A pair of (TX, RX) pins configured for CAN communication
13+
pub trait Pins: sealed::Sealed {
14+
/// The CAN peripheral that uses these pins
15+
type Instance;
16+
}
17+
18+
/// Implements sealed::Sealed and Pins for a (TX, RX) pair of pins associated with a CAN peripheral
19+
/// The alternate function number can be specified after each pin name.
20+
macro_rules! pins {
21+
($($PER:ident => ($tx:ident<$txaf:ident>, $rx:ident<$rxaf:ident>),)+) => {
22+
$(
23+
impl crate::can::sealed::Sealed for ($tx<crate::gpio::Alternate<$txaf, Input<Floating>>>, $rx<crate::gpio::Alternate<$rxaf, Input<Floating>>>) {}
24+
impl crate::can::Pins for ($tx<crate::gpio::Alternate<$txaf, Input<Floating>>>, $rx<crate::gpio::Alternate<$rxaf, Input<Floating>>>) {
25+
type Instance = $PER;
26+
}
27+
)+
28+
}
29+
}
30+
31+
mod common_pins {
32+
use crate::gpio::{
33+
gpioa::{PA11, PA12},
34+
gpiob::{PB8, PB9},
35+
gpiod::{PD0, PD1},
36+
Floating, Input, AF9,
37+
};
38+
use crate::pac::CAN1;
39+
40+
// All STM32L4 models with CAN support these pins
41+
pins! {
42+
CAN1 => (PA12<AF9>, PA11<AF9>),
43+
CAN1 => (PD1<AF9>, PD0<AF9>),
44+
CAN1 => (PB9<AF9>, PB8<AF9>),
45+
}
46+
}
47+
48+
#[cfg(feature = "stm32l4x1")]
49+
mod pb13_pb12_af10 {
50+
use crate::gpio::{
51+
gpiob::{PB12, PB13},
52+
Floating, Input, AF10,
53+
};
54+
use crate::pac::CAN1;
55+
pins! { CAN1 => (PB13<AF10>, PB12<AF10>), }
56+
}
57+
58+
/// Enable/disable peripheral
59+
pub trait Enable: sealed::Sealed {
60+
/// Enables this peripheral by setting the associated enable bit in an RCC enable register
61+
fn enable(apb: &mut APB1R1);
62+
}
63+
64+
impl crate::can::sealed::Sealed for crate::pac::CAN1 {}
65+
66+
impl crate::can::Enable for crate::pac::CAN1 {
67+
#[inline(always)]
68+
fn enable(apb: &mut APB1R1) {
69+
// Enable peripheral clock
70+
apb.enr().modify(|_, w| w.can1en().set_bit());
71+
apb.rstr().modify(|_, w| w.can1rst().set_bit());
72+
apb.rstr().modify(|_, w| w.can1rst().clear_bit());
73+
}
74+
}
75+
76+
/// Interface to the CAN peripheral.
77+
pub struct Can<Instance, Pins> {
78+
can: Instance,
79+
pins: Pins,
80+
}
81+
82+
impl<Instance, P> Can<Instance, P>
83+
where
84+
Instance: Enable,
85+
P: Pins<Instance = Instance>,
86+
{
87+
/// Creates a CAN interface.
88+
pub fn new(apb: &mut APB1R1, can: Instance, pins: P) -> Can<Instance, P> {
89+
Instance::enable(apb);
90+
Can { can, pins }
91+
}
92+
93+
// Split the peripheral back into its components.
94+
pub fn split(self) -> (Instance, P) {
95+
(self.can, self.pins)
96+
}
97+
}
98+
99+
unsafe impl<Pins> bxcan::Instance for Can<CAN1, Pins> {
100+
const REGISTERS: *mut bxcan::RegisterBlock = CAN1::ptr() as *mut _;
101+
}
102+
103+
unsafe impl<Pins> bxcan::FilterOwner for Can<CAN1, Pins> {
104+
const NUM_FILTER_BANKS: u8 = 14;
105+
}
106+
107+
unsafe impl<Pins> bxcan::MasterInstance for Can<CAN1, Pins> {}

src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@ pub mod traits;
6868
feature = "stm32l4x6"
6969
))]
7070
pub mod adc;
71+
#[cfg(any(feature = "stm32l4x1", feature = "stm32l4x5",))]
72+
pub mod can;
7173
#[cfg(any(
7274
feature = "stm32l4x1",
7375
feature = "stm32l4x2",

0 commit comments

Comments
 (0)