CAN: Use the same testing code for BXCAN and FDCAN h/w.

This commit is contained in:
Corey Schuhen 2024-03-27 19:43:19 +10:00
parent 2217b80278
commit 8d43fb4da4
3 changed files with 163 additions and 194 deletions

View File

@ -6,17 +6,19 @@
#[path = "../common.rs"] #[path = "../common.rs"]
mod common; mod common;
use common::*; use common::*;
use defmt::assert;
use embassy_executor::Spawner; use embassy_executor::Spawner;
use embassy_stm32::bind_interrupts; use embassy_stm32::bind_interrupts;
use embassy_stm32::can::bx::filter::Mask32; use embassy_stm32::can::bx::filter::Mask32;
use embassy_stm32::can::bx::{Fifo, Frame, StandardId}; use embassy_stm32::can::bx::Fifo;
use embassy_stm32::can::{Can, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, TxInterruptHandler}; use embassy_stm32::can::{Can, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, TxInterruptHandler};
use embassy_stm32::gpio::{Input, Pull}; use embassy_stm32::gpio::{Input, Pull};
use embassy_stm32::peripherals::CAN1; use embassy_stm32::peripherals::CAN1;
use embassy_time::{Duration, Instant}; use embassy_time::Duration;
use {defmt_rtt as _, panic_probe as _}; use {defmt_rtt as _, panic_probe as _};
mod can_common;
use can_common::*;
bind_interrupts!(struct Irqs { bind_interrupts!(struct Irqs {
CAN1_RX0 => Rx0InterruptHandler<CAN1>; CAN1_RX0 => Rx0InterruptHandler<CAN1>;
CAN1_RX1 => Rx1InterruptHandler<CAN1>; CAN1_RX1 => Rx1InterruptHandler<CAN1>;
@ -29,6 +31,11 @@ async fn main(_spawner: Spawner) {
let p = embassy_stm32::init(config()); let p = embassy_stm32::init(config());
info!("Hello World!"); info!("Hello World!");
let options = TestOptions {
max_latency: Duration::from_micros(1200),
max_buffered: 2,
};
let can = peri!(p, CAN); let can = peri!(p, CAN);
let tx = peri!(p, CAN_TX); let tx = peri!(p, CAN_TX);
let mut rx = peri!(p, CAN_RX); let mut rx = peri!(p, CAN_RX);
@ -58,40 +65,13 @@ async fn main(_spawner: Spawner) {
info!("Can configured"); info!("Can configured");
let mut i: u8 = 0; run_can_tests(&mut can, &options).await;
loop {
let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), &[i]).unwrap();
info!("Transmitting frame..."); // Test again with a split
let tx_ts = Instant::now(); let (mut tx, mut rx) = can.split();
can.write(&tx_frame).await; run_split_can_tests(&mut tx, &mut rx, &options).await;
let envelope = can.read().await.unwrap();
info!("Frame received!");
info!("loopback time {}", envelope.ts);
info!("loopback frame {=u8}", envelope.frame.data()[0]);
let latency = envelope.ts.saturating_duration_since(tx_ts);
info!("loopback latency {} us", latency.as_micros());
// Theoretical minimum latency is 55us, actual is usually ~80us
const MIN_LATENCY: Duration = Duration::from_micros(50);
const MAX_LATENCY: Duration = Duration::from_micros(150);
assert!(
MIN_LATENCY <= latency && latency <= MAX_LATENCY,
"{} <= {} <= {}",
MIN_LATENCY,
latency,
MAX_LATENCY
);
i += 1;
if i > 10 {
break;
}
}
info!("Test OK"); info!("Test OK");
cortex_m::asm::bkpt(); cortex_m::asm::bkpt();
} }

View File

@ -0,0 +1,112 @@
use defmt::{assert, *};
use embassy_stm32::can;
use embassy_time::{Duration, Instant};
#[derive(Clone, Copy, Debug)]
pub struct TestOptions {
pub max_latency: Duration,
pub max_buffered: u8,
}
pub async fn run_can_tests<'d, T: can::Instance>(can: &mut can::Can<'d, T>, options: &TestOptions) {
let mut i: u8 = 0;
loop {
//let tx_frame = can::frame::Frame::new_standard(0x123, &[i, 0x12 as u8, 0x34 as u8, 0x56 as u8, 0x78 as u8, 0x9A as u8, 0xBC as u8 ]).unwrap();
let tx_frame = can::frame::Frame::new_standard(0x123, &[i; 1]).unwrap();
//info!("Transmitting frame...");
let tx_ts = Instant::now();
can.write(&tx_frame).await;
let (frame, timestamp) = can.read().await.unwrap().parts();
//info!("Frame received!");
// Check data.
assert!(i == frame.data()[0], "{} == {}", i, frame.data()[0]);
//info!("loopback time {}", timestamp);
//info!("loopback frame {=u8}", frame.data()[0]);
let latency = timestamp.saturating_duration_since(tx_ts);
info!("loopback latency {} us", latency.as_micros());
// Theoretical minimum latency is 55us, actual is usually ~80us
const MIN_LATENCY: Duration = Duration::from_micros(50);
// Was failing at 150 but we are not getting a real time stamp. I'm not
// sure if there are other delays
assert!(
MIN_LATENCY <= latency && latency <= options.max_latency,
"{} <= {} <= {}",
MIN_LATENCY,
latency,
options.max_latency
);
i += 1;
if i > 5 {
break;
}
}
// Below here, check that we can receive from both FIFO0 and FIFO1
// Above we configured FIFO1 for extended ID packets. There are only 3 slots
// in each FIFO so make sure we write enough to fill them both up before reading.
for i in 0..options.max_buffered {
// Try filling up the RX FIFO0 buffers
//let tx_frame = if 0 != (i & 0x01) {
let tx_frame = if i < options.max_buffered / 2 {
info!("Transmitting standard frame {}", i);
can::frame::Frame::new_standard(0x123, &[i; 1]).unwrap()
} else {
info!("Transmitting extended frame {}", i);
can::frame::Frame::new_extended(0x1232344, &[i; 1]).unwrap()
};
can.write(&tx_frame).await;
}
// Try and receive all 6 packets
for _i in 0..options.max_buffered {
let (frame, _ts) = can.read().await.unwrap().parts();
match frame.id() {
embedded_can::Id::Extended(_id) => {
info!("Extended received! {}", frame.data()[0]);
//info!("Extended received! {:x} {} {}", id.as_raw(), frame.data()[0], i);
}
embedded_can::Id::Standard(_id) => {
info!("Standard received! {}", frame.data()[0]);
//info!("Standard received! {:x} {} {}", id.as_raw(), frame.data()[0], i);
}
}
}
}
pub async fn run_split_can_tests<'d, T: can::Instance>(
tx: &mut can::CanTx<'d, T>,
rx: &mut can::CanRx<'d, T>,
options: &TestOptions,
) {
for i in 0..options.max_buffered {
// Try filling up the RX FIFO0 buffers
//let tx_frame = if 0 != (i & 0x01) {
let tx_frame = if i < options.max_buffered / 2 {
info!("Transmitting standard frame {}", i);
can::frame::Frame::new_standard(0x123, &[i; 1]).unwrap()
} else {
info!("Transmitting extended frame {}", i);
can::frame::Frame::new_extended(0x1232344, &[i; 1]).unwrap()
};
tx.write(&tx_frame).await;
}
// Try and receive all 6 packets
for _i in 0..options.max_buffered {
let (frame, _ts) = rx.read().await.unwrap().parts();
match frame.id() {
embedded_can::Id::Extended(_id) => {
info!("Extended received! {}", frame.data()[0]);
}
embedded_can::Id::Standard(_id) => {
info!("Standard received! {}", frame.data()[0]);
}
}
}
}

View File

@ -6,13 +6,15 @@
#[path = "../common.rs"] #[path = "../common.rs"]
mod common; mod common;
use common::*; use common::*;
use defmt::assert;
use embassy_executor::Spawner; use embassy_executor::Spawner;
use embassy_stm32::peripherals::*; use embassy_stm32::peripherals::*;
use embassy_stm32::{bind_interrupts, can, Config}; use embassy_stm32::{bind_interrupts, can, Config};
use embassy_time::{Duration, Instant}; use embassy_time::Duration;
use {defmt_rtt as _, panic_probe as _}; use {defmt_rtt as _, panic_probe as _};
mod can_common;
use can_common::*;
bind_interrupts!(struct Irqs2 { bind_interrupts!(struct Irqs2 {
FDCAN2_IT0 => can::IT0InterruptHandler<FDCAN2>; FDCAN2_IT0 => can::IT0InterruptHandler<FDCAN2>;
FDCAN2_IT1 => can::IT1InterruptHandler<FDCAN2>; FDCAN2_IT1 => can::IT1InterruptHandler<FDCAN2>;
@ -22,14 +24,8 @@ bind_interrupts!(struct Irqs1 {
FDCAN1_IT1 => can::IT1InterruptHandler<FDCAN1>; FDCAN1_IT1 => can::IT1InterruptHandler<FDCAN1>;
}); });
struct TestOptions {
config: Config,
max_latency: Duration,
second_fifo_working: bool,
}
#[cfg(any(feature = "stm32h755zi", feature = "stm32h753zi", feature = "stm32h563zi"))] #[cfg(any(feature = "stm32h755zi", feature = "stm32h753zi", feature = "stm32h563zi"))]
fn options() -> TestOptions { fn options() -> (Config, TestOptions) {
use embassy_stm32::rcc; use embassy_stm32::rcc;
info!("H75 config"); info!("H75 config");
let mut c = config(); let mut c = config();
@ -38,15 +34,17 @@ fn options() -> TestOptions {
mode: rcc::HseMode::Oscillator, mode: rcc::HseMode::Oscillator,
}); });
c.rcc.mux.fdcansel = rcc::mux::Fdcansel::HSE; c.rcc.mux.fdcansel = rcc::mux::Fdcansel::HSE;
TestOptions { (
config: c, c,
max_latency: Duration::from_micros(1200), TestOptions {
second_fifo_working: false, max_latency: Duration::from_micros(1200),
} max_buffered: 3,
},
)
} }
#[cfg(any(feature = "stm32h7a3zi"))] #[cfg(any(feature = "stm32h7a3zi"))]
fn options() -> TestOptions { fn options() -> (Config, TestOptions) {
use embassy_stm32::rcc; use embassy_stm32::rcc;
info!("H7a config"); info!("H7a config");
let mut c = config(); let mut c = config();
@ -55,29 +53,33 @@ fn options() -> TestOptions {
mode: rcc::HseMode::Oscillator, mode: rcc::HseMode::Oscillator,
}); });
c.rcc.mux.fdcansel = rcc::mux::Fdcansel::HSE; c.rcc.mux.fdcansel = rcc::mux::Fdcansel::HSE;
TestOptions { (
config: c, c,
max_latency: Duration::from_micros(1200), TestOptions {
second_fifo_working: false, max_latency: Duration::from_micros(1200),
} max_buffered: 3,
},
)
} }
#[cfg(any(feature = "stm32g491re", feature = "stm32g431cb"))] #[cfg(any(feature = "stm32g491re", feature = "stm32g431cb"))]
fn options() -> TestOptions { fn options() -> (Config, TestOptions) {
info!("G4 config"); info!("G4 config");
TestOptions { (
config: config(), config(),
max_latency: Duration::from_micros(500), TestOptions {
second_fifo_working: true, max_latency: Duration::from_micros(500),
} max_buffered: 6,
},
)
} }
#[embassy_executor::main] #[embassy_executor::main]
async fn main(_spawner: Spawner) { async fn main(_spawner: Spawner) {
//let peripherals = embassy_stm32::init(config()); //let peripherals = embassy_stm32::init(config());
let options = options(); let (config, options) = options();
let peripherals = embassy_stm32::init(options.config); let peripherals = embassy_stm32::init(config);
let mut can = can::CanConfigurator::new(peripherals.FDCAN1, peripherals.PB8, peripherals.PB9, Irqs1); let mut can = can::CanConfigurator::new(peripherals.FDCAN1, peripherals.PB8, peripherals.PB9, Irqs1);
let mut can2 = can::CanConfigurator::new(peripherals.FDCAN2, peripherals.PB12, peripherals.PB13, Irqs2); let mut can2 = can::CanConfigurator::new(peripherals.FDCAN2, peripherals.PB12, peripherals.PB13, Irqs2);
@ -98,141 +100,16 @@ async fn main(_spawner: Spawner) {
let mut can = can.into_internal_loopback_mode(); let mut can = can.into_internal_loopback_mode();
let mut can2 = can2.into_internal_loopback_mode(); let mut can2 = can2.into_internal_loopback_mode();
run_can_tests(&mut can, &options).await;
run_can_tests(&mut can2, &options).await;
info!("CAN Configured"); info!("CAN Configured");
let mut i: u8 = 0;
loop {
let tx_frame = can::frame::Frame::new_standard(0x123, &[i; 1]).unwrap();
info!("Transmitting frame...");
let tx_ts = Instant::now();
can.write(&tx_frame).await;
let (frame, timestamp) = can.read().await.unwrap().parts();
info!("Frame received!");
// Check data.
assert!(i == frame.data()[0], "{} == {}", i, frame.data()[0]);
info!("loopback time {}", timestamp);
info!("loopback frame {=u8}", frame.data()[0]);
let latency = timestamp.saturating_duration_since(tx_ts);
info!("loopback latency {} us", latency.as_micros());
// Theoretical minimum latency is 55us, actual is usually ~80us
const MIN_LATENCY: Duration = Duration::from_micros(50);
// Was failing at 150 but we are not getting a real time stamp. I'm not
// sure if there are other delays
assert!(
MIN_LATENCY <= latency && latency <= options.max_latency,
"{} <= {} <= {}",
MIN_LATENCY,
latency,
options.max_latency
);
i += 1;
if i > 10 {
break;
}
}
let mut i: u8 = 0;
loop {
let tx_frame = can::frame::Frame::new_standard(0x123, &[i; 1]).unwrap();
info!("Transmitting frame...");
let tx_ts = Instant::now();
can2.write(&tx_frame).await;
let (frame, timestamp) = can2.read().await.unwrap().parts();
info!("Frame received!");
//print_regs().await;
// Check data.
assert!(i == frame.data()[0], "{} == {}", i, frame.data()[0]);
info!("loopback time {}", timestamp);
info!("loopback frame {=u8}", frame.data()[0]);
let latency = timestamp.saturating_duration_since(tx_ts);
info!("loopback latency {} us", latency.as_micros());
// Theoretical minimum latency is 55us, actual is usually ~80us
const MIN_LATENCY: Duration = Duration::from_micros(50);
// Was failing at 150 but we are not getting a real time stamp. I'm not
// sure if there are other delays
assert!(
MIN_LATENCY <= latency && latency <= options.max_latency,
"{} <= {} <= {}",
MIN_LATENCY,
latency,
options.max_latency
);
i += 1;
if i > 10 {
break;
}
}
let max_buffered = if options.second_fifo_working { 6 } else { 3 };
// Below here, check that we can receive from both FIFO0 and FIFO0
// Above we configured FIFO1 for extended ID packets. There are only 3 slots
// in each FIFO so make sure we write enough to fill them both up before reading.
for i in 0..3 {
// Try filling up the RX FIFO0 buffers with standard packets
let tx_frame = can::frame::Frame::new_standard(0x123, &[i; 1]).unwrap();
info!("Transmitting frame {}", i);
can.write(&tx_frame).await;
}
for i in 3..max_buffered {
// Try filling up the RX FIFO0 buffers with extended packets
let tx_frame = can::frame::Frame::new_extended(0x1232344, &[i; 1]).unwrap();
info!("Transmitting frame {}", i);
can.write(&tx_frame).await;
}
// Try and receive all 6 packets
for i in 0..max_buffered {
let (frame, _ts) = can.read().await.unwrap().parts();
match frame.id() {
embedded_can::Id::Extended(id) => {
info!("Extended received! {:x} {} {}", id.as_raw(), frame.data()[0], i);
}
embedded_can::Id::Standard(id) => {
info!("Standard received! {:x} {} {}", id.as_raw(), frame.data()[0], i);
}
}
}
// Test again with a split // Test again with a split
let (mut tx, mut rx) = can.split(); let (mut tx, mut rx) = can.split();
for i in 0..3 { let (mut tx2, mut rx2) = can2.split();
// Try filling up the RX FIFO0 buffers with standard packets run_split_can_tests(&mut tx, &mut rx, &options).await;
let tx_frame = can::frame::Frame::new_standard(0x123, &[i; 1]).unwrap(); run_split_can_tests(&mut tx2, &mut rx2, &options).await;
info!("Transmitting frame {}", i);
tx.write(&tx_frame).await;
}
for i in 3..max_buffered {
// Try filling up the RX FIFO0 buffers with extended packets
let tx_frame = can::frame::Frame::new_extended(0x1232344, &[i; 1]).unwrap();
info!("Transmitting frame {}", i);
tx.write(&tx_frame).await;
}
// Try and receive all 6 packets
for i in 0..max_buffered {
let (frame, _ts) = rx.read().await.unwrap().parts();
match frame.id() {
embedded_can::Id::Extended(id) => {
info!("Extended received! {:x} {} {}", id.as_raw(), frame.data()[0], i);
}
embedded_can::Id::Standard(id) => {
info!("Standard received! {:x} {} {}", id.as_raw(), frame.data()[0], i);
}
}
}
info!("Test OK"); info!("Test OK");
cortex_m::asm::bkpt(); cortex_m::asm::bkpt();