Rust examples
Real excerpts from the buildable STM32G474 targets. The linked source files contain complete imports, clock setup, interrupt bindings, and error handling.
Configure classical CAN
FDCAN2 is wired to PB12/PB13. Both nodes must use the same nominal bit rate.
let mut can = can::CanConfigurator::new(
p.FDCAN2,
p.PB12,
p.PB13,
Irqs,
);
can.set_bitrate(500_000);
can.properties().set_standard_filter(
StandardFilterSlot::_0,
StandardFilter::accept_all_into_fifo0(),
);
let mut can: Can = can.into_normal_mode();
Send a frame and await an echo
let data = [0xCA, 0xFE, seq, 0x00];
let frame = Frame::new_standard(0x123, &data).unwrap();
can.write(&frame).await;
match with_timeout(Duration::from_millis(700), can.read()).await {
Ok(Ok(envelope)) => {
let is_echo = match envelope.frame.id() {
embedded_can::Id::Standard(id) => id.as_raw() == 0x456,
embedded_can::Id::Extended(_) => false,
};
if is_echo
&& envelope.frame.data().get(0..3) == Some(&data[0..3])
{
info!("echo received");
} else {
warn!("unexpected response");
}
}
Ok(Err(error)) => error!("RX error: {:?}", error),
Err(_) => warn!("response timeout"),
}
Receive and reply
loop {
match can.read().await {
Ok(envelope) => {
let echo = Frame::new_standard(
0x456,
envelope.frame.data(),
).unwrap();
can.write(&echo).await;
}
Err(error) => error!("RX error: {:?}", error),
}
}
Configure CAN FD with BRS
The FD examples route FDCAN to the 170 MHz PCLK1 source, then configure separate arbitration and data rates.
config.rcc.mux.fdcansel = Fdcansel::PCLK1;
let p = embassy_stm32::init(config);
let mut can = can::CanConfigurator::new(
p.FDCAN2,
p.PB12,
p.PB13,
Irqs,
);
can.set_bitrate(1_000_000);
can.set_fd_data_bitrate(2_000_000, true); // TDC enabled
let mut can: Can = can.into_normal_mode();
Build a 64-byte FD frame
let mut data = [0xAAu8; 64];
data[0..4].copy_from_slice(&seq.to_le_bytes());
data[4..8].copy_from_slice(&tx_ticks.to_le_bytes());
let header = Header::new_fd(
embedded_can::StandardId::new(0x100).unwrap().into(),
64,
false, // data frame, not RTR
true, // enable bit-rate switching
);
let frame = FdFrame::new(header, &data).unwrap();
can.write_fd(&frame).await;
Check every CAN target
cd firmware/rust_bringup/stm32g4
cargo check --release \
--bin can_tx --bin can_rx \
--bin can_fd_tx --bin can_fd_rx
API stability
These examples use the Embassy revision pinned by the repository submodule. Upstream Embassy CAN APIs may differ, so build against the checkout rather than copying the snippets into an unrelated dependency version.