Skip to content

Commit 78b94dc

Browse files
committed
Add tests
1 parent 199b3c2 commit 78b94dc

File tree

6 files changed

+174
-4
lines changed

6 files changed

+174
-4
lines changed

.cargo/config.toml

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,5 @@
11
[target.thumbv8m.main-none-eabihf]
22
runner = 'arm-none-eabi-gdb'
3-
rustflags = [
4-
# LLD (shipped with the Rust toolchain) is used as the default linker
5-
"-C", "link-arg=-Tlink.x",
6-
]
73

84
[build]
95
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
@@ -77,6 +77,7 @@ cortex-m-log = { version = "0.8.0", features = ["itm", "semihosting", "log-integ
7777
cortex-m-semihosting = "0.5.0"
7878
panic-itm = { version = "~0.4.1" }
7979
panic-semihosting = "0.6"
80+
embedded-test = "0.6.1"
8081

8182
[profile.release]
8283
codegen-units = 1 # better optimizations
@@ -91,3 +92,11 @@ required-features = ["stm32h503"]
9192
[[example]]
9293
name = "i2c"
9394
required-features = ["stm32h503"]
95+
96+
[[test]]
97+
name = "nucleo-h533"
98+
harness = false
99+
required-features = ["stm32h533", "defmt"]
100+
101+
[lib]
102+
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
@@ -2,6 +2,7 @@
22

33
cfg_if::cfg_if! {
44
if #[cfg(any(feature = "log-itm"))] {
5+
#[cfg(not(test))]
56
use panic_itm as _;
67

78
use lazy_static::lazy_static;
@@ -33,6 +34,7 @@ cfg_if::cfg_if! {
3334

3435
}
3536
else if #[cfg(any(feature = "log-rtt"))] {
37+
#[cfg(not(test))]
3638
use panic_rtt_target as _;
3739

3840
use log::{Level, Metadata, Record, LevelFilter};
@@ -65,6 +67,7 @@ cfg_if::cfg_if! {
6567
}
6668
}
6769
else if #[cfg(any(feature = "log-semihost"))] {
70+
#[cfg(not(test))]
6871
use panic_semihosting as _;
6972

7073
use lazy_static::lazy_static;
@@ -88,6 +91,7 @@ cfg_if::cfg_if! {
8891
}
8992
}
9093
else {
94+
#[cfg(not(test))]
9195
use panic_halt as _;
9296
pub fn init() {}
9397
}

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)