Skip to content

Add tests #52

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 0 additions & 5 deletions .cargo/config.toml
Original file line number Diff line number Diff line change
@@ -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)
18 changes: 18 additions & 0 deletions build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
use std::env;

fn main() {
if env::var("TARGET").unwrap() != "thumbv8m.main-none-eabihf" {
return;
}

// 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");
}
}
4 changes: 4 additions & 0 deletions examples/utilities/logger.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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};
Expand Down Expand Up @@ -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;
Expand All @@ -110,6 +113,7 @@ cfg_if::cfg_if! {
}
}
else {
#[cfg(not(test))]
use panic_halt as _;
pub fn init() {}
}
Expand Down
67 changes: 67 additions & 0 deletions tests/common/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
use fugit::{ExtU32, MicrosDurationU32};
use stm32h5xx_hal::stm32;

#[non_exhaustive]
pub struct Timer<const CYCLES_PER_US: u32>;

impl<const CYCLES_PER_US: u32> Timer<CYCLES_PER_US> {
#[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<const CYCLES_PER_US: u32>(
timer: &Timer<CYCLES_PER_US>,
pin: u8,
timeout: MicrosDurationU32,
) -> Result<MicrosDurationU32, ErrorTimedOut> {
await_p(timer, || is_pax_low(pin), timeout)
}

#[allow(dead_code)]
pub fn await_hi<const CYCLES_PER_US: u32>(
timer: &Timer<CYCLES_PER_US>,
pin: u8,
timeout: MicrosDurationU32,
) -> Result<MicrosDurationU32, ErrorTimedOut> {
await_p(timer, || !is_pax_low(pin), timeout)
}

#[allow(dead_code)]
pub fn await_p<const CYCLES_PER_US: u32>(
timer: &Timer<CYCLES_PER_US>,
mut p: impl FnMut() -> bool,
timeout: MicrosDurationU32,
) -> Result<MicrosDurationU32, ErrorTimedOut> {
let before = timer.now();

loop {
let passed_time = timer.now() - before;
if p() {
return Ok(passed_time);
}
if passed_time > timeout {
return Err(ErrorTimedOut);
}
}
}
Comment on lines +33 to +67
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I put up #61. Maybe that will help with some of these waiting operations?

119 changes: 119 additions & 0 deletions tests/nucleo-h533.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
#![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);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this be used to set the core clock frequency? Currently, it is set to 250MHz on line 113, so deriving the cycles per µs is incorrect here.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, I just put up #61, which should help with doing this derivation

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};

#[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 mut pin = gpioa.pa8.into_push_pull_output();
let pin_num = pin.pin_id();

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 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
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));
}

#[test]
fn gpio_settings() {
use super::*;

let (gpioa, _) = init();
let pin = gpioa.pa8;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason you're picking PA8 for all these tests?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, not really. I can spread out to a couple more pins. Perhaps both sides of 8 since I believe some settings are split into different registers for pin 0..=7 and 8..=15?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you think we should test more ports too, like B, C etc?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could conceivably do all the pins if you converted each to an ErasedPin and shoved them all into an array? If you wanted to you could modify the Parts struct defined here to implement that instead of doing it here?


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) {
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)
}