From ed82dfc569cc92e1383f918990f0b963c6d7eaf5 Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Fri, 30 May 2025 00:46:31 +0200 Subject: [PATCH 1/5] Add tests --- .cargo/config.toml | 5 --- Cargo.toml | 9 ++++ build.rs | 14 +++++++ examples/utilities/logger.rs | 4 ++ tests/common/mod.rs | 67 ++++++++++++++++++++++++++++++ tests/nucleo-h533.rs | 80 ++++++++++++++++++++++++++++++++++++ 6 files changed, 174 insertions(+), 5 deletions(-) create mode 100644 build.rs create mode 100644 tests/common/mod.rs create mode 100644 tests/nucleo-h533.rs diff --git a/.cargo/config.toml b/.cargo/config.toml index d2012bd..c04e055 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -1,10 +1,5 @@ [target.thumbv8m.main-none-eabihf] runner = 'probe-rs run --connect-under-reset' -rustflags = [ - # LLD (shipped with the Rust toolchain) is used as the default linker - "-C", "link-arg=-Tlink.x", - "-C", "link-arg=-Tdefmt.x", -] [build] target = "thumbv8m.main-none-eabihf" # Cortex-M33F (with FPU) diff --git a/Cargo.toml b/Cargo.toml index 24c3e0c..22c9a50 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -79,6 +79,7 @@ cortex-m-semihosting = "0.5.0" panic-itm = { version = "~0.4.1" } panic-probe = "0.3.2" panic-semihosting = "0.6" +embedded-test = "0.6.1" [profile.release] codegen-units = 1 # better optimizations @@ -92,3 +93,11 @@ name = "blinky" [[example]] name = "i2c" required-features = ["stm32h503"] + +[[test]] +name = "nucleo-h533" +harness = false +required-features = ["stm32h533", "defmt"] + +[lib] +test = false diff --git a/build.rs b/build.rs new file mode 100644 index 0000000..e7f6595 --- /dev/null +++ b/build.rs @@ -0,0 +1,14 @@ +use std::env; + +fn main() { + // stm32 specific + println!("cargo:rustc-link-arg=-Tlink.x"); + + // add linker script for embedded-test!! + println!("cargo::rustc-link-arg-tests=-Tembedded-test.x"); + + // Check if the `defmt` feature is enabled, and if so link its linker script + if env::var("CARGO_FEATURE_DEFMT").is_ok() { + println!("cargo:rustc-link-arg=-Tdefmt.x"); + } +} diff --git a/examples/utilities/logger.rs b/examples/utilities/logger.rs index e47f78b..c3980e4 100644 --- a/examples/utilities/logger.rs +++ b/examples/utilities/logger.rs @@ -13,6 +13,7 @@ cfg_if::cfg_if! { cfg_if::cfg_if! { if #[cfg(any(feature = "log-itm"))] { + #[cfg(not(test))] use panic_itm as _; use lazy_static::lazy_static; @@ -55,6 +56,7 @@ cfg_if::cfg_if! { pub fn init() {} } else if #[cfg(any(feature = "log-rtt"))] { + #[cfg(not(test))] use panic_rtt_target as _; use log::{Level, Metadata, Record, LevelFilter}; @@ -87,6 +89,7 @@ cfg_if::cfg_if! { } } else if #[cfg(any(feature = "log-semihost"))] { + #[cfg(not(test))] use panic_semihosting as _; use lazy_static::lazy_static; @@ -110,6 +113,7 @@ cfg_if::cfg_if! { } } else { + #[cfg(not(test))] use panic_halt as _; pub fn init() {} } diff --git a/tests/common/mod.rs b/tests/common/mod.rs new file mode 100644 index 0000000..01314d2 --- /dev/null +++ b/tests/common/mod.rs @@ -0,0 +1,67 @@ +use fugit::{ExtU32, MicrosDurationU32}; +use stm32h5xx_hal::stm32; + +#[non_exhaustive] +pub struct Timer; + +impl Timer { + #[allow(dead_code)] + pub fn enable_timer(cp: &mut stm32::CorePeripherals) -> Self { + cp.DCB.enable_trace(); + cp.DWT.enable_cycle_counter(); + + Timer + } + + /// Returns duration since timer start + pub fn now(&self) -> MicrosDurationU32 { + (stm32::DWT::cycle_count() / CYCLES_PER_US).micros() + } +} + +#[allow(dead_code)] +pub fn is_pax_low(pin: u8) -> bool { + let gpioa = unsafe { &*stm32::GPIOA::PTR }; + gpioa.idr().read().id(pin).is_low() +} + +#[allow(dead_code)] +#[derive(Debug, defmt::Format)] +pub struct ErrorTimedOut; + +#[allow(dead_code)] +pub fn await_lo( + timer: &Timer, + pin: u8, + timeout: MicrosDurationU32, +) -> Result { + await_p(timer, || is_pax_low(pin), timeout) +} + +#[allow(dead_code)] +pub fn await_hi( + timer: &Timer, + pin: u8, + timeout: MicrosDurationU32, +) -> Result { + await_p(timer, || !is_pax_low(pin), timeout) +} + +#[allow(dead_code)] +pub fn await_p( + timer: &Timer, + mut p: impl FnMut() -> bool, + timeout: MicrosDurationU32, +) -> Result { + let before = timer.now(); + + loop { + let passed_time = timer.now() - before; + if p() { + return Ok(passed_time); + } + if passed_time > timeout { + return Err(ErrorTimedOut); + } + } +} diff --git a/tests/nucleo-h533.rs b/tests/nucleo-h533.rs new file mode 100644 index 0000000..f87bc71 --- /dev/null +++ b/tests/nucleo-h533.rs @@ -0,0 +1,80 @@ +#![no_std] +#![no_main] + +#[path = "../examples/utilities/mod.rs"] +mod utils; + +mod common; + +use fugit::HertzU32; +use hal::stm32; +use stm32h5xx_hal::{self as hal, gpio}; + +pub const F_SYS: HertzU32 = HertzU32::MHz(16); +pub const CYCLES_PER_US: u32 = F_SYS.raw() / 1_000_000; + +use crate::common::is_pax_low; +use embedded_hal::delay::DelayNs; +use fugit::RateExtU32; +use stm32h5xx_hal::{ + delay::Delay, gpio::GpioExt, pwr::PwrExt, rcc::RccExt, stm32::GPIOA, +}; + +#[embedded_test::tests] +mod tests { + #[test] + fn gpio_push_pull() { + use super::*; + + let (gpioa, mut delay) = init(); + + let _pa1_important_dont_use_as_output = gpioa.pa1.into_floating_input(); + let mut pin = gpioa.pa8.into_push_pull_output(); + let pin_num = 8; // PA8 + + pin.set_high(); + delay.delay_ms(1); // Give the pin plenty of time to go high + assert!(!is_pax_low(pin_num)); + + pin.set_low(); + delay.delay_ms(1); // Give the pin plenty of time to go low + assert!(is_pax_low(pin_num)); + } + + #[test] + fn gpio_open_drain() { + use super::*; + + let (gpioa, mut delay) = init(); + let _pa1_important_dont_use_as_output = gpioa.pa1.into_floating_input(); + let mut pin = gpioa.pa8.into_open_drain_output().internal_pull_up(on); + let pin_num = 8; // PA8 + + pin.set_high(); + delay.delay_ms(1); // Give the pin plenty of time to go high + assert!(pin.is_high()); + assert!(!is_pax_low(pin_num)); + + pin.set_low(); + delay.delay_ms(1); // Give the pin plenty of time to go low + assert!(pin.is_low()); + assert!(is_pax_low(pin_num)); + } +} + +fn init() -> (gpio::gpioa::Parts, Delay) { + utils::logger::init(); + let cp = stm32::CorePeripherals::take().unwrap(); + let dp = stm32::Peripherals::take().unwrap(); + let pwr = dp.PWR.constrain(); + let pwrcfg = pwr.vos0().freeze(); + + // Constrain and Freeze clock + let rcc = dp.RCC.constrain(); + let ccdr = rcc.sys_ck(250u32.MHz()).freeze(pwrcfg, &dp.SBS); + + let delay = Delay::new(cp.SYST, &ccdr.clocks); + let gpioa = dp.GPIOA.split(ccdr.peripheral.GPIOA); + + (gpioa, delay) +} From 07bc6e9034f733193d0d4380ee94269207c02efb Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Fri, 30 May 2025 22:00:19 +0200 Subject: [PATCH 2/5] Add test for pull up/down resistors --- tests/nucleo-h533.rs | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/tests/nucleo-h533.rs b/tests/nucleo-h533.rs index f87bc71..bcea2ff 100644 --- a/tests/nucleo-h533.rs +++ b/tests/nucleo-h533.rs @@ -16,21 +16,36 @@ pub const CYCLES_PER_US: u32 = F_SYS.raw() / 1_000_000; use crate::common::is_pax_low; use embedded_hal::delay::DelayNs; use fugit::RateExtU32; -use stm32h5xx_hal::{ - delay::Delay, gpio::GpioExt, pwr::PwrExt, rcc::RccExt, stm32::GPIOA, -}; +use stm32h5xx_hal::{delay::Delay, gpio::GpioExt, pwr::PwrExt, rcc::RccExt}; #[embedded_test::tests] mod tests { + use stm32h5xx_hal::gpio::{PinExt, Pull}; + + #[test] + fn gpio_resistors() { + use super::*; + + let (gpioa, mut delay) = init(); + + let mut pin = gpioa.pa8.into_pull_down_input(); + let pin_num = pin.pin_id(); + + delay.delay_ms(1); // Give the pin plenty of time to go low + assert!(is_pax_low(pin_num)); + + pin.set_internal_resistor(Pull::Up); + delay.delay_ms(1); // Give the pin plenty of time to go high + assert!(!is_pax_low(pin_num)); + } #[test] fn gpio_push_pull() { use super::*; let (gpioa, mut delay) = init(); - let _pa1_important_dont_use_as_output = gpioa.pa1.into_floating_input(); let mut pin = gpioa.pa8.into_push_pull_output(); - let pin_num = 8; // PA8 + let pin_num = pin.pin_id(); pin.set_high(); delay.delay_ms(1); // Give the pin plenty of time to go high @@ -46,9 +61,9 @@ mod tests { use super::*; let (gpioa, mut delay) = init(); - let _pa1_important_dont_use_as_output = gpioa.pa1.into_floating_input(); - let mut pin = gpioa.pa8.into_open_drain_output().internal_pull_up(on); - let pin_num = 8; // PA8 + + let mut pin = gpioa.pa8.into_open_drain_output().internal_pull_up(true); + let pin_num = pin.pin_id(); pin.set_high(); delay.delay_ms(1); // Give the pin plenty of time to go high From c91c7c8c97c4c453e759097a727a4c2c43a7a47a Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Fri, 30 May 2025 22:29:47 +0200 Subject: [PATCH 3/5] Fix tests not running on the device --- Cargo.toml | 9 --------- build.rs | 5 +++++ 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 22c9a50..24c3e0c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -79,7 +79,6 @@ cortex-m-semihosting = "0.5.0" panic-itm = { version = "~0.4.1" } panic-probe = "0.3.2" panic-semihosting = "0.6" -embedded-test = "0.6.1" [profile.release] codegen-units = 1 # better optimizations @@ -93,11 +92,3 @@ name = "blinky" [[example]] name = "i2c" required-features = ["stm32h503"] - -[[test]] -name = "nucleo-h533" -harness = false -required-features = ["stm32h533", "defmt"] - -[lib] -test = false diff --git a/build.rs b/build.rs index e7f6595..362da9a 100644 --- a/build.rs +++ b/build.rs @@ -1,6 +1,11 @@ use std::env; fn main() { + + if env::var("TARGET").unwrap() != "thumbv8m.main-none-eabihf" { + return; + } + // stm32 specific println!("cargo:rustc-link-arg=-Tlink.x"); From 096c59944541c7b2b1ea192642187c5eb2405787 Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Sun, 8 Jun 2025 20:32:17 +0200 Subject: [PATCH 4/5] fmt --- build.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/build.rs b/build.rs index 362da9a..6a957f8 100644 --- a/build.rs +++ b/build.rs @@ -1,7 +1,6 @@ use std::env; fn main() { - if env::var("TARGET").unwrap() != "thumbv8m.main-none-eabihf" { return; } From a80205696dc5be4c1aa8380e2e0542d6e5b276b7 Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Sun, 8 Jun 2025 20:39:30 +0200 Subject: [PATCH 5/5] Add test for lots of gpio settings --- tests/nucleo-h533.rs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/tests/nucleo-h533.rs b/tests/nucleo-h533.rs index bcea2ff..c3b20b3 100644 --- a/tests/nucleo-h533.rs +++ b/tests/nucleo-h533.rs @@ -75,6 +75,30 @@ mod tests { assert!(pin.is_low()); assert!(is_pax_low(pin_num)); } + + #[test] + fn gpio_settings() { + use super::*; + + let (gpioa, _) = init(); + let pin = gpioa.pa8; + + let mut pin = pin.into_floating_input(); + + pin.set_internal_resistor(Pull::Up); + + pin.set_internal_resistor(Pull::Down); + + let pin = pin.into_analog(); + let pin = pin.into_push_pull_output(); + let pin = pin.into_open_drain_output(); + let pin: gpio::Pin<'A', 8, gpio::Alternate<7>> = pin.into_alternate(); + let mut pin: gpio::Pin<'A', 8, gpio::Alternate<15>> = + pin.into_alternate(); + + pin.set_speed(gpio::Speed::Low); + pin.set_speed(gpio::Speed::VeryHigh); + } } fn init() -> (gpio::gpioa::Parts, Delay) {