mirror of
https://github.com/embassy-rs/embassy.git
synced 2024-11-25 16:23:10 +00:00
CAN: Use the same testing code for BXCAN and FDCAN h/w.
This commit is contained in:
parent
2217b80278
commit
8d43fb4da4
@ -6,17 +6,19 @@
|
||||
#[path = "../common.rs"]
|
||||
mod common;
|
||||
use common::*;
|
||||
use defmt::assert;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_stm32::bind_interrupts;
|
||||
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::gpio::{Input, Pull};
|
||||
use embassy_stm32::peripherals::CAN1;
|
||||
use embassy_time::{Duration, Instant};
|
||||
use embassy_time::Duration;
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
mod can_common;
|
||||
use can_common::*;
|
||||
|
||||
bind_interrupts!(struct Irqs {
|
||||
CAN1_RX0 => Rx0InterruptHandler<CAN1>;
|
||||
CAN1_RX1 => Rx1InterruptHandler<CAN1>;
|
||||
@ -29,6 +31,11 @@ async fn main(_spawner: Spawner) {
|
||||
let p = embassy_stm32::init(config());
|
||||
info!("Hello World!");
|
||||
|
||||
let options = TestOptions {
|
||||
max_latency: Duration::from_micros(1200),
|
||||
max_buffered: 2,
|
||||
};
|
||||
|
||||
let can = peri!(p, CAN);
|
||||
let tx = peri!(p, CAN_TX);
|
||||
let mut rx = peri!(p, CAN_RX);
|
||||
@ -58,40 +65,13 @@ async fn main(_spawner: Spawner) {
|
||||
|
||||
info!("Can configured");
|
||||
|
||||
let mut i: u8 = 0;
|
||||
loop {
|
||||
let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), &[i]).unwrap();
|
||||
run_can_tests(&mut can, &options).await;
|
||||
|
||||
info!("Transmitting frame...");
|
||||
let tx_ts = Instant::now();
|
||||
can.write(&tx_frame).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;
|
||||
}
|
||||
}
|
||||
// Test again with a split
|
||||
let (mut tx, mut rx) = can.split();
|
||||
run_split_can_tests(&mut tx, &mut rx, &options).await;
|
||||
|
||||
info!("Test OK");
|
||||
|
||||
cortex_m::asm::bkpt();
|
||||
}
|
||||
|
112
tests/stm32/src/bin/can_common.rs
Normal file
112
tests/stm32/src/bin/can_common.rs
Normal 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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -6,13 +6,15 @@
|
||||
#[path = "../common.rs"]
|
||||
mod common;
|
||||
use common::*;
|
||||
use defmt::assert;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_stm32::peripherals::*;
|
||||
use embassy_stm32::{bind_interrupts, can, Config};
|
||||
use embassy_time::{Duration, Instant};
|
||||
use embassy_time::Duration;
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
mod can_common;
|
||||
use can_common::*;
|
||||
|
||||
bind_interrupts!(struct Irqs2 {
|
||||
FDCAN2_IT0 => can::IT0InterruptHandler<FDCAN2>;
|
||||
FDCAN2_IT1 => can::IT1InterruptHandler<FDCAN2>;
|
||||
@ -22,14 +24,8 @@ bind_interrupts!(struct Irqs1 {
|
||||
FDCAN1_IT1 => can::IT1InterruptHandler<FDCAN1>;
|
||||
});
|
||||
|
||||
struct TestOptions {
|
||||
config: Config,
|
||||
max_latency: Duration,
|
||||
second_fifo_working: bool,
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "stm32h755zi", feature = "stm32h753zi", feature = "stm32h563zi"))]
|
||||
fn options() -> TestOptions {
|
||||
fn options() -> (Config, TestOptions) {
|
||||
use embassy_stm32::rcc;
|
||||
info!("H75 config");
|
||||
let mut c = config();
|
||||
@ -38,15 +34,17 @@ fn options() -> TestOptions {
|
||||
mode: rcc::HseMode::Oscillator,
|
||||
});
|
||||
c.rcc.mux.fdcansel = rcc::mux::Fdcansel::HSE;
|
||||
TestOptions {
|
||||
config: c,
|
||||
max_latency: Duration::from_micros(1200),
|
||||
second_fifo_working: false,
|
||||
}
|
||||
(
|
||||
c,
|
||||
TestOptions {
|
||||
max_latency: Duration::from_micros(1200),
|
||||
max_buffered: 3,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "stm32h7a3zi"))]
|
||||
fn options() -> TestOptions {
|
||||
fn options() -> (Config, TestOptions) {
|
||||
use embassy_stm32::rcc;
|
||||
info!("H7a config");
|
||||
let mut c = config();
|
||||
@ -55,29 +53,33 @@ fn options() -> TestOptions {
|
||||
mode: rcc::HseMode::Oscillator,
|
||||
});
|
||||
c.rcc.mux.fdcansel = rcc::mux::Fdcansel::HSE;
|
||||
TestOptions {
|
||||
config: c,
|
||||
max_latency: Duration::from_micros(1200),
|
||||
second_fifo_working: false,
|
||||
}
|
||||
(
|
||||
c,
|
||||
TestOptions {
|
||||
max_latency: Duration::from_micros(1200),
|
||||
max_buffered: 3,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "stm32g491re", feature = "stm32g431cb"))]
|
||||
fn options() -> TestOptions {
|
||||
fn options() -> (Config, TestOptions) {
|
||||
info!("G4 config");
|
||||
TestOptions {
|
||||
config: config(),
|
||||
max_latency: Duration::from_micros(500),
|
||||
second_fifo_working: true,
|
||||
}
|
||||
(
|
||||
config(),
|
||||
TestOptions {
|
||||
max_latency: Duration::from_micros(500),
|
||||
max_buffered: 6,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(_spawner: Spawner) {
|
||||
//let peripherals = embassy_stm32::init(config());
|
||||
|
||||
let options = options();
|
||||
let peripherals = embassy_stm32::init(options.config);
|
||||
let (config, options) = options();
|
||||
let peripherals = embassy_stm32::init(config);
|
||||
|
||||
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);
|
||||
@ -98,141 +100,16 @@ async fn main(_spawner: Spawner) {
|
||||
let mut can = can.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");
|
||||
|
||||
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
|
||||
let (mut tx, mut rx) = can.split();
|
||||
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);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
let (mut tx2, mut rx2) = can2.split();
|
||||
run_split_can_tests(&mut tx, &mut rx, &options).await;
|
||||
run_split_can_tests(&mut tx2, &mut rx2, &options).await;
|
||||
|
||||
info!("Test OK");
|
||||
cortex_m::asm::bkpt();
|
||||
|
Loading…
Reference in New Issue
Block a user