diff options
| author | Corey Schuhen <[email protected]> | 2024-01-17 21:13:24 +1000 |
|---|---|---|
| committer | Corey Schuhen <[email protected]> | 2024-01-31 05:40:05 +1000 |
| commit | 6e1047395d56dbbd1aa1a0352bdd3147e3994c5b (patch) | |
| tree | 681520439b8e80cf36c3162c033d89484da276b0 /tests | |
| parent | 1698f4dbc3b5f4e561c3edd20246af63c22da507 (diff) | |
HIL test for STM32 FDCAN support.
Internal loopback.
fdcan: use common.rs for HIL test.
Fix tests.
Fix tests.
Fix tests
Add HIL tests for H7 even though they are a bit crippled.
CI fixes
Bah
Test
bah
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/stm32/Cargo.toml | 16 | ||||
| -rw-r--r-- | tests/stm32/src/bin/fdcan.rs | 243 |
2 files changed, 254 insertions, 5 deletions
diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml index bf85f05d2..b8b52c076 100644 --- a/tests/stm32/Cargo.toml +++ b/tests/stm32/Cargo.toml | |||
| @@ -14,11 +14,11 @@ stm32f429zi = ["embassy-stm32/stm32f429zi", "chrono", "eth", "stop", "can", "not | |||
| 14 | stm32f446re = ["embassy-stm32/stm32f446re", "chrono", "stop", "can", "not-gpdma", "dac", "sdmmc"] | 14 | stm32f446re = ["embassy-stm32/stm32f446re", "chrono", "stop", "can", "not-gpdma", "dac", "sdmmc"] |
| 15 | stm32f767zi = ["embassy-stm32/stm32f767zi", "chrono", "not-gpdma", "eth", "rng"] | 15 | stm32f767zi = ["embassy-stm32/stm32f767zi", "chrono", "not-gpdma", "eth", "rng"] |
| 16 | stm32g071rb = ["embassy-stm32/stm32g071rb", "cm0", "not-gpdma", "dac"] | 16 | stm32g071rb = ["embassy-stm32/stm32g071rb", "cm0", "not-gpdma", "dac"] |
| 17 | stm32g491re = ["embassy-stm32/stm32g491re", "chrono", "stop", "not-gpdma", "rng"] | 17 | stm32g491re = ["embassy-stm32/stm32g491re", "chrono", "stop", "not-gpdma", "rng", "fdcan"] |
| 18 | stm32h563zi = ["embassy-stm32/stm32h563zi", "chrono", "eth", "rng"] | 18 | stm32h563zi = ["embassy-stm32/stm32h563zi", "chrono", "eth", "rng", "fdcan"] |
| 19 | stm32h753zi = ["embassy-stm32/stm32h753zi", "chrono", "not-gpdma", "eth", "rng"] | 19 | stm32h753zi = ["embassy-stm32/stm32h753zi", "chrono", "not-gpdma", "eth", "rng", "fdcan"] |
| 20 | stm32h755zi = ["embassy-stm32/stm32h755zi-cm7", "chrono", "not-gpdma", "eth", "dac", "rng"] | 20 | stm32h755zi = ["embassy-stm32/stm32h755zi-cm7", "chrono", "not-gpdma", "eth", "dac", "rng", "fdcan"] |
| 21 | stm32h7a3zi = ["embassy-stm32/stm32h7a3zi", "not-gpdma", "rng"] | 21 | stm32h7a3zi = ["embassy-stm32/stm32h7a3zi", "not-gpdma", "rng", "fdcan"] |
| 22 | stm32l073rz = ["embassy-stm32/stm32l073rz", "cm0", "not-gpdma", "rng"] | 22 | stm32l073rz = ["embassy-stm32/stm32l073rz", "cm0", "not-gpdma", "rng"] |
| 23 | stm32l152re = ["embassy-stm32/stm32l152re", "chrono", "not-gpdma"] | 23 | stm32l152re = ["embassy-stm32/stm32l152re", "chrono", "not-gpdma"] |
| 24 | stm32l496zg = ["embassy-stm32/stm32l496zg", "not-gpdma", "rng"] | 24 | stm32l496zg = ["embassy-stm32/stm32l496zg", "not-gpdma", "rng"] |
| @@ -37,6 +37,7 @@ sdmmc = [] | |||
| 37 | stop = ["embassy-stm32/low-power", "embassy-stm32/low-power-debug-with-sleep"] | 37 | stop = ["embassy-stm32/low-power", "embassy-stm32/low-power-debug-with-sleep"] |
| 38 | chrono = ["embassy-stm32/chrono", "dep:chrono"] | 38 | chrono = ["embassy-stm32/chrono", "dep:chrono"] |
| 39 | can = [] | 39 | can = [] |
| 40 | fdcan = [] | ||
| 40 | ble = ["dep:embassy-stm32-wpan", "embassy-stm32-wpan/ble"] | 41 | ble = ["dep:embassy-stm32-wpan", "embassy-stm32-wpan/ble"] |
| 41 | mac = ["dep:embassy-stm32-wpan", "embassy-stm32-wpan/mac"] | 42 | mac = ["dep:embassy-stm32-wpan", "embassy-stm32-wpan/mac"] |
| 42 | embassy-stm32-wpan = [] | 43 | embassy-stm32-wpan = [] |
| @@ -97,6 +98,11 @@ path = "src/bin/eth.rs" | |||
| 97 | required-features = [ "eth",] | 98 | required-features = [ "eth",] |
| 98 | 99 | ||
| 99 | [[bin]] | 100 | [[bin]] |
| 101 | name = "fdcan" | ||
| 102 | path = "src/bin/fdcan.rs" | ||
| 103 | required-features = [ "fdcan",] | ||
| 104 | |||
| 105 | [[bin]] | ||
| 100 | name = "gpio" | 106 | name = "gpio" |
| 101 | path = "src/bin/gpio.rs" | 107 | path = "src/bin/gpio.rs" |
| 102 | required-features = [] | 108 | required-features = [] |
diff --git a/tests/stm32/src/bin/fdcan.rs b/tests/stm32/src/bin/fdcan.rs new file mode 100644 index 000000000..7363eaa16 --- /dev/null +++ b/tests/stm32/src/bin/fdcan.rs | |||
| @@ -0,0 +1,243 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | // required-features: fdcan | ||
| 5 | |||
| 6 | #[path = "../common.rs"] | ||
| 7 | mod common; | ||
| 8 | use common::*; | ||
| 9 | use defmt::assert; | ||
| 10 | use embassy_executor::Spawner; | ||
| 11 | use embassy_stm32::peripherals::*; | ||
| 12 | use embassy_stm32::{bind_interrupts, can, Config}; | ||
| 13 | use embassy_time::{Duration, Instant}; | ||
| 14 | use {defmt_rtt as _, panic_probe as _}; | ||
| 15 | |||
| 16 | bind_interrupts!(struct Irqs { | ||
| 17 | FDCAN1_IT0 => can::IT0InterruptHandler<FDCAN1>; | ||
| 18 | FDCAN1_IT1 => can::IT1InterruptHandler<FDCAN1>; | ||
| 19 | }); | ||
| 20 | |||
| 21 | struct TestOptions { | ||
| 22 | config: Config, | ||
| 23 | max_latency: Duration, | ||
| 24 | second_fifo_working: bool, | ||
| 25 | } | ||
| 26 | |||
| 27 | #[cfg(any(feature = "stm32h755zi", feature = "stm32h753zi", feature = "stm32h563zi"))] | ||
| 28 | fn options() -> TestOptions { | ||
| 29 | use embassy_stm32::rcc; | ||
| 30 | info!("H75 config"); | ||
| 31 | let mut c = config(); | ||
| 32 | c.rcc.hse = Some(rcc::Hse { | ||
| 33 | freq: embassy_stm32::time::Hertz(25_000_000), | ||
| 34 | mode: rcc::HseMode::Oscillator, | ||
| 35 | }); | ||
| 36 | c.rcc.fdcan_clock_source = rcc::FdCanClockSource::HSE; | ||
| 37 | TestOptions { | ||
| 38 | config: c, | ||
| 39 | max_latency: Duration::from_micros(3800), | ||
| 40 | second_fifo_working: false, | ||
| 41 | } | ||
| 42 | } | ||
| 43 | |||
| 44 | #[cfg(any(feature = "stm32h7a3zi"))] | ||
| 45 | fn options() -> TestOptions { | ||
| 46 | use embassy_stm32::rcc; | ||
| 47 | info!("H7a config"); | ||
| 48 | let mut c = config(); | ||
| 49 | c.rcc.hse = Some(rcc::Hse { | ||
| 50 | freq: embassy_stm32::time::Hertz(25_000_000), | ||
| 51 | mode: rcc::HseMode::Oscillator, | ||
| 52 | }); | ||
| 53 | c.rcc.fdcan_clock_source = rcc::FdCanClockSource::HSE; | ||
| 54 | TestOptions { | ||
| 55 | config: c, | ||
| 56 | max_latency: Duration::from_micros(5500), | ||
| 57 | second_fifo_working: false, | ||
| 58 | } | ||
| 59 | } | ||
| 60 | |||
| 61 | #[cfg(any(feature = "stm32g491re"))] | ||
| 62 | fn options() -> TestOptions { | ||
| 63 | info!("G4 config"); | ||
| 64 | TestOptions { | ||
| 65 | config: config(), | ||
| 66 | max_latency: Duration::from_micros(500), | ||
| 67 | second_fifo_working: true, | ||
| 68 | } | ||
| 69 | } | ||
| 70 | |||
| 71 | #[embassy_executor::main] | ||
| 72 | async fn main(_spawner: Spawner) { | ||
| 73 | //let peripherals = embassy_stm32::init(config()); | ||
| 74 | |||
| 75 | let options = options(); | ||
| 76 | let peripherals = embassy_stm32::init(options.config); | ||
| 77 | |||
| 78 | let mut can = can::Fdcan::new(peripherals.FDCAN1, peripherals.PB8, peripherals.PB9, Irqs); | ||
| 79 | |||
| 80 | // 250k bps | ||
| 81 | can.set_bitrate(250_000); | ||
| 82 | |||
| 83 | can.can.set_extended_filter( | ||
| 84 | can::filter::ExtendedFilterSlot::_0, | ||
| 85 | can::filter::ExtendedFilter::accept_all_into_fifo1(), | ||
| 86 | ); | ||
| 87 | |||
| 88 | let mut can = can.into_internal_loopback_mode(); | ||
| 89 | |||
| 90 | info!("CAN Configured"); | ||
| 91 | |||
| 92 | let mut i: u8 = 0; | ||
| 93 | loop { | ||
| 94 | let tx_frame = can::TxFrame::new( | ||
| 95 | can::TxFrameHeader { | ||
| 96 | len: 1, | ||
| 97 | frame_format: can::FrameFormat::Standard, | ||
| 98 | id: can::StandardId::new(0x123).unwrap().into(), | ||
| 99 | bit_rate_switching: false, | ||
| 100 | marker: None, | ||
| 101 | }, | ||
| 102 | &[i], | ||
| 103 | ) | ||
| 104 | .unwrap(); | ||
| 105 | |||
| 106 | info!("Transmitting frame..."); | ||
| 107 | let tx_ts = Instant::now(); | ||
| 108 | can.write(&tx_frame).await; | ||
| 109 | |||
| 110 | let envelope = can.read().await.unwrap(); | ||
| 111 | info!("Frame received!"); | ||
| 112 | |||
| 113 | // Check data. | ||
| 114 | assert!(i == envelope.data()[0], "{} == {}", i, envelope.data()[0]); | ||
| 115 | |||
| 116 | info!("loopback time {}", envelope.header.time_stamp); | ||
| 117 | info!("loopback frame {=u8}", envelope.data()[0]); | ||
| 118 | let latency = envelope.timestamp.saturating_duration_since(tx_ts); | ||
| 119 | info!("loopback latency {} us", latency.as_micros()); | ||
| 120 | |||
| 121 | // Theoretical minimum latency is 55us, actual is usually ~80us | ||
| 122 | const MIN_LATENCY: Duration = Duration::from_micros(50); | ||
| 123 | // Was failing at 150 but we are not getting a real time stamp. I'm not | ||
| 124 | // sure if there are other delays | ||
| 125 | assert!( | ||
| 126 | MIN_LATENCY <= latency && latency <= options.max_latency, | ||
| 127 | "{} <= {} <= {}", | ||
| 128 | MIN_LATENCY, | ||
| 129 | latency, | ||
| 130 | options.max_latency | ||
| 131 | ); | ||
| 132 | |||
| 133 | i += 1; | ||
| 134 | if i > 10 { | ||
| 135 | break; | ||
| 136 | } | ||
| 137 | } | ||
| 138 | |||
| 139 | let max_buffered = if options.second_fifo_working { 6 } else { 3 }; | ||
| 140 | |||
| 141 | // Below here, check that we can receive from both FIFO0 and FIFO0 | ||
| 142 | // Above we configured FIFO1 for extended ID packets. There are only 3 slots | ||
| 143 | // in each FIFO so make sure we write enough to fill them both up before reading. | ||
| 144 | for i in 0..3 { | ||
| 145 | // Try filling up the RX FIFO0 buffers with standard packets | ||
| 146 | let tx_frame = can::TxFrame::new( | ||
| 147 | can::TxFrameHeader { | ||
| 148 | len: 1, | ||
| 149 | frame_format: can::FrameFormat::Standard, | ||
| 150 | id: can::StandardId::new(0x123).unwrap().into(), | ||
| 151 | bit_rate_switching: false, | ||
| 152 | marker: None, | ||
| 153 | }, | ||
| 154 | &[i], | ||
| 155 | ) | ||
| 156 | .unwrap(); | ||
| 157 | info!("Transmitting frame {}", i); | ||
| 158 | can.write(&tx_frame).await; | ||
| 159 | } | ||
| 160 | for i in 3..max_buffered { | ||
| 161 | // Try filling up the RX FIFO0 buffers with extended packets | ||
| 162 | let tx_frame = can::TxFrame::new( | ||
| 163 | can::TxFrameHeader { | ||
| 164 | len: 1, | ||
| 165 | frame_format: can::FrameFormat::Standard, | ||
| 166 | id: can::ExtendedId::new(0x1232344).unwrap().into(), | ||
| 167 | bit_rate_switching: false, | ||
| 168 | marker: None, | ||
| 169 | }, | ||
| 170 | &[i], | ||
| 171 | ) | ||
| 172 | .unwrap(); | ||
| 173 | |||
| 174 | info!("Transmitting frame {}", i); | ||
| 175 | can.write(&tx_frame).await; | ||
| 176 | } | ||
| 177 | |||
| 178 | // Try and receive all 6 packets | ||
| 179 | for i in 0..max_buffered { | ||
| 180 | let envelope = can.read().await.unwrap(); | ||
| 181 | match envelope.header.id { | ||
| 182 | can::Id::Extended(id) => { | ||
| 183 | info!("Extended received! {:x} {} {}", id.as_raw(), envelope.data()[0], i); | ||
| 184 | } | ||
| 185 | can::Id::Standard(id) => { | ||
| 186 | info!("Standard received! {:x} {} {}", id.as_raw(), envelope.data()[0], i); | ||
| 187 | } | ||
| 188 | } | ||
| 189 | } | ||
| 190 | |||
| 191 | // Test again with a split | ||
| 192 | let (mut tx, mut rx) = can.split(); | ||
| 193 | for i in 0..3 { | ||
| 194 | // Try filling up the RX FIFO0 buffers with standard packets | ||
| 195 | let tx_frame = can::TxFrame::new( | ||
| 196 | can::TxFrameHeader { | ||
| 197 | len: 1, | ||
| 198 | frame_format: can::FrameFormat::Standard, | ||
| 199 | id: can::StandardId::new(0x123).unwrap().into(), | ||
| 200 | bit_rate_switching: false, | ||
| 201 | marker: None, | ||
| 202 | }, | ||
| 203 | &[i], | ||
| 204 | ) | ||
| 205 | .unwrap(); | ||
| 206 | |||
| 207 | info!("Transmitting frame {}", i); | ||
| 208 | tx.write(&tx_frame).await; | ||
| 209 | } | ||
| 210 | for i in 3..max_buffered { | ||
| 211 | // Try filling up the RX FIFO0 buffers with extended packets | ||
| 212 | let tx_frame = can::TxFrame::new( | ||
| 213 | can::TxFrameHeader { | ||
| 214 | len: 1, | ||
| 215 | frame_format: can::FrameFormat::Standard, | ||
| 216 | id: can::ExtendedId::new(0x1232344).unwrap().into(), | ||
| 217 | bit_rate_switching: false, | ||
| 218 | marker: None, | ||
| 219 | }, | ||
| 220 | &[i], | ||
| 221 | ) | ||
| 222 | .unwrap(); | ||
| 223 | |||
| 224 | info!("Transmitting frame {}", i); | ||
| 225 | tx.write(&tx_frame).await; | ||
| 226 | } | ||
| 227 | |||
| 228 | // Try and receive all 6 packets | ||
| 229 | for i in 0..max_buffered { | ||
| 230 | let envelope = rx.read().await.unwrap(); | ||
| 231 | match envelope.header.id { | ||
| 232 | can::Id::Extended(id) => { | ||
| 233 | info!("Extended received! {:x} {} {}", id.as_raw(), envelope.data()[0], i); | ||
| 234 | } | ||
| 235 | can::Id::Standard(id) => { | ||
| 236 | info!("Standard received! {:x} {} {}", id.as_raw(), envelope.data()[0], i); | ||
| 237 | } | ||
| 238 | } | ||
| 239 | } | ||
| 240 | |||
| 241 | info!("Test OK"); | ||
| 242 | cortex_m::asm::bkpt(); | ||
| 243 | } | ||
