Skip to content

Controller Area Network (CAN) #215

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 43 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
8319e5d
can: Add basic types
timokroeger May 1, 2020
0974b15
can: API constructors
timokroeger May 1, 2020
80ae548
can: Basic configuration to enable the peripheral
timokroeger May 1, 2020
8ddd345
can: Basic transmission
timokroeger May 1, 2020
e2861e8
can: More sophisticated transmit logic
timokroeger May 1, 2020
2a121bc
can: Use UAVCAN transmit approach
timokroeger May 2, 2020
e937ed8
can: Document `Tx::transmit()`
timokroeger May 3, 2020
77e66b1
can: clippy suggestions
timokroeger May 3, 2020
d6fb675
can: Implement `Ord` for ids
timokroeger May 3, 2020
c0869f4
can: Impl `Ord` trait for frames
timokroeger May 6, 2020
a178097
can: TX interrupt support
timokroeger May 6, 2020
a1e6c61
can: Interrupt based CAN tx example
timokroeger May 6, 2020
2b585cc
can: Split pin assigment from constructor
timokroeger May 8, 2020
26a7b5f
can: Basic RX code
timokroeger May 8, 2020
33e680f
can: Combine both FIFOs in one receiver
timokroeger May 9, 2020
ae2e3f6
can: Improve interrupt enableding/disabling
timokroeger May 9, 2020
4cd5caa
can: Update the examples
timokroeger May 9, 2020
c5d9766
can: Fix priority ordering
timokroeger May 10, 2020
0365b81
can: Update doc comments
timokroeger May 11, 2020
7d15ec7
can: Make `set_bit_timing()` safe
timokroeger May 11, 2020
d83a034
can: Refactor transmitter code
timokroeger May 11, 2020
c77b837
can: Make automatic wake-up configurable
timokroeger May 11, 2020
28dc2ec
can: Configurable filters
timokroeger May 12, 2020
6dff5c2
can: Fix stm32f103 build
timokroeger May 12, 2020
a3d6295
can: Silent and Loop-back-mode
timokroeger May 13, 2020
901faa8
can: Detect RX overrun errors
timokroeger May 14, 2020
c9ac19e
can: Remove `RxError` enum
timokroeger May 16, 2020
59dfee7
can: Consistent naming for rtr bit methods
timokroeger May 16, 2020
626dc40
can: Fix the `PartialEq` trait for frames
timokroeger May 16, 2020
3128139
can: Filter bank split index for stm32f105/107
timokroeger May 16, 2020
6e6f138
can: Fix and improve filter configuration
timokroeger May 16, 2020
510daaf
can: Add advanced filter configuration
timokroeger May 16, 2020
baf7f0f
can: Documentation and example cleanup
timokroeger May 17, 2020
e3a17fe
can: RTR frames can have a DLC > 0
timokroeger May 21, 2020
ee348df
Do not build `can-loopback` when unsupported
timokroeger Aug 6, 2020
e86efb0
can: Improve advanced filter configuration
timokroeger May 23, 2020
a2e8f0d
can: Improve feature usage for examples
timokroeger Aug 30, 2020
cb801eb
can: Make `can-rtfm` example work with stm32f103
timokroeger Sep 6, 2020
f5b6d73
can: Fix PB8 PB9 pin remapping
timokroeger Oct 1, 2020
916b96c
can: Use `unsafe` for bit-banding
timokroeger Oct 2, 2020
e1b217d
Fix typos and review comments
timokroeger Oct 5, 2020
8d1732a
can: Add `Id` enum
timokroeger Oct 6, 2020
c6a095e
can: Improve RTFM example
timokroeger Oct 11, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 17 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ panic-semihosting = "0.5.2"
panic-itm = "0.4.1"
cortex-m-rtfm = "0.5"
cortex-m-semihosting = "0.3.3"
heapless = "0.4.3"
heapless = "0.5.5"
m = "0.1.1"
mfrc522 = "0.2.0"
serde_derive = "1.0.90"
Expand Down Expand Up @@ -78,7 +78,7 @@ doc = []
rt = ["stm32f1/rt"]
stm32f100 = ["stm32f1/stm32f100", "device-selected"]
stm32f101 = ["stm32f1/stm32f101", "device-selected"]
stm32f103 = ["stm32f1/stm32f103", "device-selected"]
stm32f103 = ["stm32f1/stm32f103", "device-selected", "has-can"]
stm32f105 = ["stm32f1/stm32f107", "device-selected", "connectivity"]
stm32f107 = ["stm32f1/stm32f107", "device-selected", "connectivity"]

Expand All @@ -89,7 +89,9 @@ high = ["medium"]
# Devices with 768 Kb ROM or more
xl = ["high"]
# Connectivity line devices (`stm32f105xx` and `stm32f107xx`)
connectivity = ["medium"]
connectivity = ["medium", "has-can"]
# Devices with CAN interface
has-can = []

[profile.dev]
incremental = false
Expand Down Expand Up @@ -131,3 +133,15 @@ required-features = ["rt", "medium"]
[[example]]
name = "exti"
required-features = ["rt"]

[[example]]
name = "can-echo"
required-features = ["connectivity"]

[[example]]
name = "can-loopback"
required-features = ["has-can"]

[[example]]
name = "can-rtfm"
required-features = ["has-can", "rt"]
69 changes: 69 additions & 0 deletions examples/can-echo.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
//! Simple CAN example. Requires a transceiver connected to PB5 and PB6.

#![no_main]
#![no_std]

use panic_halt as _;

use cortex_m_rt::entry;
use nb::block;
use stm32f1xx_hal::{
can::{Can, Filter, NUM_FILTER_BANKS},
pac,
prelude::*,
};

#[entry]
fn main() -> ! {
let dp = pac::Peripherals::take().unwrap();

let mut flash = dp.FLASH.constrain();
let mut rcc = dp.RCC.constrain();

// To meet CAN clock accuracy requirements an external crystal or ceramic
// resonator must be used. The blue pill has a 8MHz external crystal.
// Other boards might have a crystal with another frequency or none at all.
rcc.cfgr.use_hse(8.mhz()).freeze(&mut flash.acr);

let mut can2 = Can::new(dp.CAN2, &mut rcc.apb1);

// Select pins for CAN2.
let mut gpiob = dp.GPIOB.split(&mut rcc.apb2);
let can_rx_pin = gpiob.pb5.into_floating_input(&mut gpiob.crl);
let can_tx_pin = gpiob.pb6.into_alternate_push_pull(&mut gpiob.crl);
let mut afio = dp.AFIO.constrain(&mut rcc.apb2);
can2.assign_pins((can_tx_pin, can_rx_pin), &mut afio.mapr);

can2.configure(|config| {
// APB1 (PCLK1): 8MHz, Bit rate: 125kBit/s, Sample Point 87.5%
// Value was calculated with http://www.bittiming.can-wiki.info/
config.set_bit_timing(0x001c_0003);
});

// Filters are required to use the receiver part of CAN2.
// Because the filter banks are part of CAN1 we first need to enable CAN1
// and split the filters between the peripherals to use them for CAN2.
let mut can1 = Can::new(dp.CAN1, &mut rcc.apb1);

// Split the filters at index 0: No filters for CAN1 (unused), 28 filters
// for CAN2.
let (_filters1, mut filters2) = can1.split_filters(0).unwrap();
assert_eq!(filters2.num_available(), NUM_FILTER_BANKS);
filters2.add(&Filter::accept_all()).unwrap(); // Receive all messages.

// Split the peripheral into transmitter and receiver parts.
let mut rx = can2.take_rx(filters2).unwrap();
let mut tx = can2.take_tx().unwrap();

// Sync to the bus and start normal operation.
block!(can2.enable()).ok();

// Echo back received packages in sequence.
// See the `can-rtfm` example for an echo implementation that adheres to
// correct frame ordering based on the transfer id.
loop {
if let Ok(frame) = block!(rx.receive()) {
block!(tx.transmit(&frame)).unwrap();
}
}
}
105 changes: 105 additions & 0 deletions examples/can-loopback.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
//! Showcases advanced CAN filter capabilities.
//! Does not require additional transceiver hardware.

#![no_main]
#![no_std]

use panic_halt as _;

use cortex_m_rt::entry;
use embedded_hal::digital::v2::OutputPin;
use nb::block;
use stm32f1xx_hal::{
can::{Can, Filter, Frame, Id},
pac,
prelude::*,
};

#[entry]
fn main() -> ! {
let dp = pac::Peripherals::take().unwrap();

let mut flash = dp.FLASH.constrain();
let mut 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 mut can = Can::new(dp.CAN1, &mut rcc.apb1, dp.USB);

#[cfg(feature = "connectivity")]
let mut can = Can::new(dp.CAN1, &mut rcc.apb1);

// Use loopback mode: No pins need to be assigned to peripheral.
can.configure(|config| {
// APB1 (PCLK1): 8MHz, Bit rate: 125kBit/s, Sample Point 87.5%
// Value was calculated with http://www.bittiming.can-wiki.info/
config.set_bit_timing(0x001c_0003);
config.set_loopback(true);
config.set_silent(true);
});

// Use advanced configurations for the first three filter banks.
// More details can be found in the reference manual of the device.
#[cfg(not(feature = "connectivity"))]
let mut filters = can
.split_filters_advanced(0x0000_0006, 0xFFFF_FFFA, 0x0000_0007)
.unwrap();
#[cfg(feature = "connectivity")]
let (mut filters, _) = can
.split_filters_advanced(0x0000_0006, 0xFFFF_FFFA, 0x0000_0007, 3)
.unwrap();

assert_eq!(filters.num_available(), 8);

// 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
filters
.add(&Filter::new(Id::Standard(0)).with_mask(!0b1))
.unwrap();
filters
.add(&Filter::new(Id::Standard(0)).with_mask(!0b10))
.unwrap();

// 2x 29bit id filter bank: Matches 4, 5
filters.add(&Filter::new(Id::Standard(4))).unwrap();
filters.add(&Filter::new(Id::Standard(5))).unwrap();

// 4x 11bit id filter bank: Matches 8, 9, 10, 11
filters.add(&Filter::new(Id::Standard(8))).unwrap();
filters.add(&Filter::new(Id::Standard(9))).unwrap();
filters.add(&Filter::new(Id::Standard(10))).unwrap();
filters.add(&Filter::new(Id::Standard(11))).unwrap();

// Split the peripheral into transmitter and receiver parts.
let mut rx = can.take_rx(filters).unwrap();
let mut tx = can.take_tx().unwrap();

// Sync to the bus and start normal operation.
block!(can.enable()).ok();

// Some messages shall pass the filters.
for &id in &[0, 1, 2, 4, 5, 8, 9, 10, 11] {
let frame_tx = Frame::new(Id::Standard(id), &[id as u8]).unwrap();
block!(tx.transmit(&frame_tx)).unwrap();
let frame_rx = block!(rx.receive()).unwrap();
assert_eq!(frame_tx, frame_rx);
}

// Others must be filtered out.
for &id in &[3, 6, 7, 12] {
let frame_tx = Frame::new(Id::Standard(id), &[id as u8]).unwrap();
block!(tx.transmit(&frame_tx)).unwrap();
assert!(rx.receive().is_err());
}

let mut gpiob = dp.GPIOB.split(&mut rcc.apb2);
let mut led = gpiob.pb9.into_push_pull_output(&mut gpiob.crh);
led.set_high().unwrap();

loop {}
}
Loading