Skip to content

Commit ed82dfc

Browse files
committed
Add tests
1 parent dcf2744 commit ed82dfc

File tree

6 files changed

+174
-5
lines changed

6 files changed

+174
-5
lines changed

.cargo/config.toml

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,5 @@
11
[target.thumbv8m.main-none-eabihf]
22
runner = 'probe-rs run --connect-under-reset'
3-
rustflags = [
4-
# LLD (shipped with the Rust toolchain) is used as the default linker
5-
"-C", "link-arg=-Tlink.x",
6-
"-C", "link-arg=-Tdefmt.x",
7-
]
83

94
[build]
105
target = "thumbv8m.main-none-eabihf" # Cortex-M33F (with FPU)

Cargo.toml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ cortex-m-semihosting = "0.5.0"
7979
panic-itm = { version = "~0.4.1" }
8080
panic-probe = "0.3.2"
8181
panic-semihosting = "0.6"
82+
embedded-test = "0.6.1"
8283

8384
[profile.release]
8485
codegen-units = 1 # better optimizations
@@ -92,3 +93,11 @@ name = "blinky"
9293
[[example]]
9394
name = "i2c"
9495
required-features = ["stm32h503"]
96+
97+
[[test]]
98+
name = "nucleo-h533"
99+
harness = false
100+
required-features = ["stm32h533", "defmt"]
101+
102+
[lib]
103+
test = false

build.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
use std::env;
2+
3+
fn main() {
4+
// stm32 specific
5+
println!("cargo:rustc-link-arg=-Tlink.x");
6+
7+
// add linker script for embedded-test!!
8+
println!("cargo::rustc-link-arg-tests=-Tembedded-test.x");
9+
10+
// Check if the `defmt` feature is enabled, and if so link its linker script
11+
if env::var("CARGO_FEATURE_DEFMT").is_ok() {
12+
println!("cargo:rustc-link-arg=-Tdefmt.x");
13+
}
14+
}

examples/utilities/logger.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ cfg_if::cfg_if! {
1313

1414
cfg_if::cfg_if! {
1515
if #[cfg(any(feature = "log-itm"))] {
16+
#[cfg(not(test))]
1617
use panic_itm as _;
1718

1819
use lazy_static::lazy_static;
@@ -55,6 +56,7 @@ cfg_if::cfg_if! {
5556
pub fn init() {}
5657
}
5758
else if #[cfg(any(feature = "log-rtt"))] {
59+
#[cfg(not(test))]
5860
use panic_rtt_target as _;
5961

6062
use log::{Level, Metadata, Record, LevelFilter};
@@ -87,6 +89,7 @@ cfg_if::cfg_if! {
8789
}
8890
}
8991
else if #[cfg(any(feature = "log-semihost"))] {
92+
#[cfg(not(test))]
9093
use panic_semihosting as _;
9194

9295
use lazy_static::lazy_static;
@@ -110,6 +113,7 @@ cfg_if::cfg_if! {
110113
}
111114
}
112115
else {
116+
#[cfg(not(test))]
113117
use panic_halt as _;
114118
pub fn init() {}
115119
}

tests/common/mod.rs

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
use fugit::{ExtU32, MicrosDurationU32};
2+
use stm32h5xx_hal::stm32;
3+
4+
#[non_exhaustive]
5+
pub struct Timer<const CYCLES_PER_US: u32>;
6+
7+
impl<const CYCLES_PER_US: u32> Timer<CYCLES_PER_US> {
8+
#[allow(dead_code)]
9+
pub fn enable_timer(cp: &mut stm32::CorePeripherals) -> Self {
10+
cp.DCB.enable_trace();
11+
cp.DWT.enable_cycle_counter();
12+
13+
Timer
14+
}
15+
16+
/// Returns duration since timer start
17+
pub fn now(&self) -> MicrosDurationU32 {
18+
(stm32::DWT::cycle_count() / CYCLES_PER_US).micros()
19+
}
20+
}
21+
22+
#[allow(dead_code)]
23+
pub fn is_pax_low(pin: u8) -> bool {
24+
let gpioa = unsafe { &*stm32::GPIOA::PTR };
25+
gpioa.idr().read().id(pin).is_low()
26+
}
27+
28+
#[allow(dead_code)]
29+
#[derive(Debug, defmt::Format)]
30+
pub struct ErrorTimedOut;
31+
32+
#[allow(dead_code)]
33+
pub fn await_lo<const CYCLES_PER_US: u32>(
34+
timer: &Timer<CYCLES_PER_US>,
35+
pin: u8,
36+
timeout: MicrosDurationU32,
37+
) -> Result<MicrosDurationU32, ErrorTimedOut> {
38+
await_p(timer, || is_pax_low(pin), timeout)
39+
}
40+
41+
#[allow(dead_code)]
42+
pub fn await_hi<const CYCLES_PER_US: u32>(
43+
timer: &Timer<CYCLES_PER_US>,
44+
pin: u8,
45+
timeout: MicrosDurationU32,
46+
) -> Result<MicrosDurationU32, ErrorTimedOut> {
47+
await_p(timer, || !is_pax_low(pin), timeout)
48+
}
49+
50+
#[allow(dead_code)]
51+
pub fn await_p<const CYCLES_PER_US: u32>(
52+
timer: &Timer<CYCLES_PER_US>,
53+
mut p: impl FnMut() -> bool,
54+
timeout: MicrosDurationU32,
55+
) -> Result<MicrosDurationU32, ErrorTimedOut> {
56+
let before = timer.now();
57+
58+
loop {
59+
let passed_time = timer.now() - before;
60+
if p() {
61+
return Ok(passed_time);
62+
}
63+
if passed_time > timeout {
64+
return Err(ErrorTimedOut);
65+
}
66+
}
67+
}

tests/nucleo-h533.rs

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
#![no_std]
2+
#![no_main]
3+
4+
#[path = "../examples/utilities/mod.rs"]
5+
mod utils;
6+
7+
mod common;
8+
9+
use fugit::HertzU32;
10+
use hal::stm32;
11+
use stm32h5xx_hal::{self as hal, gpio};
12+
13+
pub const F_SYS: HertzU32 = HertzU32::MHz(16);
14+
pub const CYCLES_PER_US: u32 = F_SYS.raw() / 1_000_000;
15+
16+
use crate::common::is_pax_low;
17+
use embedded_hal::delay::DelayNs;
18+
use fugit::RateExtU32;
19+
use stm32h5xx_hal::{
20+
delay::Delay, gpio::GpioExt, pwr::PwrExt, rcc::RccExt, stm32::GPIOA,
21+
};
22+
23+
#[embedded_test::tests]
24+
mod tests {
25+
#[test]
26+
fn gpio_push_pull() {
27+
use super::*;
28+
29+
let (gpioa, mut delay) = init();
30+
31+
let _pa1_important_dont_use_as_output = gpioa.pa1.into_floating_input();
32+
let mut pin = gpioa.pa8.into_push_pull_output();
33+
let pin_num = 8; // PA8
34+
35+
pin.set_high();
36+
delay.delay_ms(1); // Give the pin plenty of time to go high
37+
assert!(!is_pax_low(pin_num));
38+
39+
pin.set_low();
40+
delay.delay_ms(1); // Give the pin plenty of time to go low
41+
assert!(is_pax_low(pin_num));
42+
}
43+
44+
#[test]
45+
fn gpio_open_drain() {
46+
use super::*;
47+
48+
let (gpioa, mut delay) = init();
49+
let _pa1_important_dont_use_as_output = gpioa.pa1.into_floating_input();
50+
let mut pin = gpioa.pa8.into_open_drain_output().internal_pull_up(on);
51+
let pin_num = 8; // PA8
52+
53+
pin.set_high();
54+
delay.delay_ms(1); // Give the pin plenty of time to go high
55+
assert!(pin.is_high());
56+
assert!(!is_pax_low(pin_num));
57+
58+
pin.set_low();
59+
delay.delay_ms(1); // Give the pin plenty of time to go low
60+
assert!(pin.is_low());
61+
assert!(is_pax_low(pin_num));
62+
}
63+
}
64+
65+
fn init() -> (gpio::gpioa::Parts, Delay) {
66+
utils::logger::init();
67+
let cp = stm32::CorePeripherals::take().unwrap();
68+
let dp = stm32::Peripherals::take().unwrap();
69+
let pwr = dp.PWR.constrain();
70+
let pwrcfg = pwr.vos0().freeze();
71+
72+
// Constrain and Freeze clock
73+
let rcc = dp.RCC.constrain();
74+
let ccdr = rcc.sys_ck(250u32.MHz()).freeze(pwrcfg, &dp.SBS);
75+
76+
let delay = Delay::new(cp.SYST, &ccdr.clocks);
77+
let gpioa = dp.GPIOA.split(ccdr.peripheral.GPIOA);
78+
79+
(gpioa, delay)
80+
}

0 commit comments

Comments
 (0)