From 957d7793ad24d39c9d0d49cf719c4843cde19eef Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Tue, 28 Jan 2025 20:55:24 +0100 Subject: [PATCH 1/8] Add pwm test --- Cargo.toml | 8 +++++ tests/pwm.rs | 93 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 101 insertions(+) create mode 100644 tests/pwm.rs diff --git a/Cargo.toml b/Cargo.toml index 17f24cc9..ea8f418f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -65,6 +65,7 @@ optional = true [dev-dependencies] cortex-m-rt = "0.7.2" defmt-rtt = "0.4.0" +defmt-test = "0.3.2" cortex-m-rtic = "1.1.4" cortex-m-semihosting = "0.3.5" panic-probe = { version = "0.3.0", features = ["print-defmt"] } @@ -130,3 +131,10 @@ required-features = ["usb"] [[example]] name = "cordic" required-features = ["cordic"] + +[[test]] +name = "pwm" +harness = false + +[lib] +test = false \ No newline at end of file diff --git a/tests/pwm.rs b/tests/pwm.rs new file mode 100644 index 00000000..20844283 --- /dev/null +++ b/tests/pwm.rs @@ -0,0 +1,93 @@ +#![no_std] +#![no_main] + +#[path ="../examples/utils/mod.rs"] +mod utils; + +use utils::logger::println; + +use core::ops::FnMut; +use core::result::Result; +use fugit::{ExtU32, MicrosDurationU32}; +use hal::delay::{DelayExt, SystDelay}; +use hal::stm32; +use stm32g4xx_hal as hal; + +#[defmt_test::tests] +mod tests { + use embedded_hal::pwm::SetDutyCycle; + use fugit::RateExtU32; + use stm32g4xx_hal::{ + delay::SYSTDelayExt, gpio::GpioExt, pwm::PwmExt, rcc::RccExt, stm32::GPIOA, + }; + + #[test] + fn foo() { + use super::*; + + let cp = stm32::CorePeripherals::take().expect("cannot take peripherals"); + let dp = stm32::Peripherals::take().expect("cannot take peripherals"); + let mut rcc = dp.RCC.constrain(); + let mut delay = cp.SYST.delay(&rcc.clocks); + + let gpioa = dp.GPIOA.split(&mut rcc); + let pin = gpioa.pa8.into_alternate(); + + let mut pwm = dp.TIM1.pwm(pin, 1000u32.Hz(), &mut rcc); + + let _ = pwm.set_duty_cycle_percent(50); + pwm.enable(); + + let gpioa = unsafe { &*GPIOA::ptr() }; + + let min: MicrosDurationU32 = 490u32.micros();// Some extra on min for cpu overhead + let max: MicrosDurationU32 = 505u32.micros(); + + println!("Awaiting rising edge..."); + await_lo(&gpioa, &mut delay, max).unwrap(); + await_hi(&gpioa, &mut delay, max).unwrap(); + + for _ in 0..10 { + // Make sure the timer half periods are within 490-505us + + let hi_duration = await_lo(&gpioa, &mut delay, max).unwrap(); + let lo_duration = await_hi(&gpioa, &mut delay, max).unwrap(); + + assert!(hi_duration > min); + assert!(lo_duration > min); + } + } +} + +#[derive(Debug)] +struct ErrorTimedOut; + +fn await_lo( + gpioa: &stm32::gpioa::RegisterBlock, + delay: &mut SystDelay, + timeout: MicrosDurationU32, +) -> Result { + await_p(|| gpioa.idr().read().idr(8).is_low(), delay, timeout) +} + +fn await_hi( + gpioa: &stm32::gpioa::RegisterBlock, + delay: &mut SystDelay, + timeout: MicrosDurationU32, +) -> Result { + await_p(|| gpioa.idr().read().idr(8).is_high(), delay, timeout) +} + +fn await_p( + mut p: impl FnMut() -> bool, + delay: &mut SystDelay, + timeout: MicrosDurationU32, +) -> Result { + for i in 0..timeout.ticks() { + if p() { + return Ok(i.micros()); + } + delay.delay(1_u32.micros()); + } + Err(ErrorTimedOut) +} From c8d1f4bc2e0004d5866334c711af9ae01134ef0a Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Tue, 28 Jan 2025 20:56:59 +0100 Subject: [PATCH 2/8] Remove log-rtt --- examples/utils/logger.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/examples/utils/logger.rs b/examples/utils/logger.rs index 07c64191..a5e38d06 100644 --- a/examples/utils/logger.rs +++ b/examples/utils/logger.rs @@ -1,6 +1,6 @@ #![allow(unsafe_code)] cfg_if::cfg_if! { - if #[cfg(all(feature = "log-rtt", feature = "defmt"))] { + if #[cfg(feature = "defmt")] { #[allow(unused_imports)] pub use defmt::{info, trace, warn, debug, error}; @@ -55,7 +55,7 @@ cfg_if::cfg_if! { } } - else if #[cfg(all(feature = "log-rtt"/*, feature = "defmt"*/))] { + else if #[cfg(feature = "defmt")] { use defmt_rtt as _; // global logger use panic_probe as _; #[allow(unused_imports)] @@ -66,9 +66,6 @@ cfg_if::cfg_if! { #[allow(dead_code)] pub fn init() {} } - else if #[cfg(all(feature = "log-rtt", not(feature = "defmt")))] { - // TODO - } else if #[cfg(feature = "log-semihost")] { use panic_semihosting as _; From 519412fe20e00ab31c694311474894732b93f988 Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Tue, 28 Jan 2025 23:27:43 +0100 Subject: [PATCH 3/8] Not working... --- Cargo.toml | 7 +++++++ tests/pwm.rs | 50 +++++++++++++++++++++++++++++++++++--------------- 2 files changed, 42 insertions(+), 15 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ea8f418f..c5a18498 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -120,6 +120,13 @@ codegen-units = 1 incremental = false lto = true +[profile.test] +opt-level = "s" +debug = true +codegen-units = 1 +incremental = false +lto = true + [[example]] name = "flash_with_rtic" required-features = ["stm32g474"] diff --git a/tests/pwm.rs b/tests/pwm.rs index 20844283..35d4d4cf 100644 --- a/tests/pwm.rs +++ b/tests/pwm.rs @@ -18,7 +18,7 @@ mod tests { use embedded_hal::pwm::SetDutyCycle; use fugit::RateExtU32; use stm32g4xx_hal::{ - delay::SYSTDelayExt, gpio::GpioExt, pwm::PwmExt, rcc::RccExt, stm32::GPIOA, + delay::SYSTDelayExt, gpio::{GpioExt, AF6}, pwm::PwmExt, rcc::RccExt, stm32::GPIOA, }; #[test] @@ -31,35 +31,55 @@ mod tests { let mut delay = cp.SYST.delay(&rcc.clocks); let gpioa = dp.GPIOA.split(&mut rcc); - let pin = gpioa.pa8.into_alternate(); + let pin: stm32g4xx_hal::gpio::gpioa::PA8> = gpioa.pa8.into_alternate(); - let mut pwm = dp.TIM1.pwm(pin, 1000u32.Hz(), &mut rcc); + //let mut pwm = dp.TIM1.pwm(pin, 1000u32.Hz(), &mut rcc); - let _ = pwm.set_duty_cycle_percent(50); - pwm.enable(); + //pwm.set_duty_cycle_percent(50).unwrap(); + //pwm.enable(); + - let gpioa = unsafe { &*GPIOA::ptr() }; + let gpioa = unsafe { &*GPIOA::PTR }; + let get_pin_state = || unsafe { (0x4800_0004 as *const u32).read_volatile() }; + + // TODO: This is a very bad way to measure time let min: MicrosDurationU32 = 490u32.micros();// Some extra on min for cpu overhead let max: MicrosDurationU32 = 505u32.micros(); - println!("Awaiting rising edge..."); - await_lo(&gpioa, &mut delay, max).unwrap(); - await_hi(&gpioa, &mut delay, max).unwrap(); + { + println!("Awaiting first rising edge..."); + //println!("{}", gpioa.odr().read().odr(8).is_high()); + println!("{}", get_pin_state()); + //let duration_until_lo = await_lo(&gpioa, &mut delay, max);//.unwrap(); + } + /* + //println!("Low..., Waited ~{}us until low", duration_until_lo); + let lo_duration = await_hi(&gpioa, &mut delay, max);//.unwrap(); + //println!("High..., Low half period: {}us", lo_duration); + } for _ in 0..10 { // Make sure the timer half periods are within 490-505us - let hi_duration = await_lo(&gpioa, &mut delay, max).unwrap(); - let lo_duration = await_hi(&gpioa, &mut delay, max).unwrap(); + let hi_duration = await_lo(&gpioa, &mut delay, max);//.unwrap(); + println!("Low..., High half period: {}us", hi_duration); + //assert!(hi_duration > min, "{} > {}", hi_duration, min); - assert!(hi_duration > min); - assert!(lo_duration > min); + let lo_duration = await_hi(&gpioa, &mut delay, max);//.unwrap(); + println!("High..., Low half period: {}us", lo_duration); + //assert!(lo_duration > min, "{} > {}", lo_duration, min); } + + println!("Done!"); + for i in (0..5).rev() { + println!("{}", i); + delay.delay(1000.millis()); + }*/ } } -#[derive(Debug)] +#[derive(Debug, defmt::Format)] struct ErrorTimedOut; fn await_lo( @@ -87,7 +107,7 @@ fn await_p( if p() { return Ok(i.micros()); } - delay.delay(1_u32.micros()); + //delay.delay(1_u32.micros()); } Err(ErrorTimedOut) } From bd876abb7c4451630b83e64b6fcdb3349fac389e Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Wed, 29 Jan 2025 22:41:13 +0100 Subject: [PATCH 4/8] Add more tests --- tests/pwm.rs | 136 +++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 106 insertions(+), 30 deletions(-) diff --git a/tests/pwm.rs b/tests/pwm.rs index 35d4d4cf..455d6fe2 100644 --- a/tests/pwm.rs +++ b/tests/pwm.rs @@ -1,7 +1,7 @@ #![no_std] #![no_main] -#[path ="../examples/utils/mod.rs"] +#[path = "../examples/utils/mod.rs"] mod utils; use utils::logger::println; @@ -15,70 +15,146 @@ use stm32g4xx_hal as hal; #[defmt_test::tests] mod tests { - use embedded_hal::pwm::SetDutyCycle; + use embedded_hal::{ + digital::{InputPin, OutputPin}, + pwm::SetDutyCycle, + }; use fugit::RateExtU32; use stm32g4xx_hal::{ - delay::SYSTDelayExt, gpio::{GpioExt, AF6}, pwm::PwmExt, rcc::RccExt, stm32::GPIOA, + delay::SYSTDelayExt, + gpio::{GpioExt, AF6}, + pwm::PwmExt, + rcc::RccExt, + stm32::GPIOA, }; + #[test] + fn gpio_push_pull() { + use super::*; + + // TODO: Is it ok to steal these? + let cp = unsafe { stm32::CorePeripherals::steal() }; + let dp = unsafe { stm32::Peripherals::steal() }; + let mut rcc = dp.RCC.constrain(); + let mut delay = cp.SYST.delay(&rcc.clocks); + + let gpioa = dp.GPIOA.split(&mut rcc); + let mut pin = gpioa.pa8.into_push_pull_output(); + + pin.set_high().unwrap(); + delay.delay(1.millis()); // Give the pin plenty of time to go high + assert!(pin.is_high().unwrap()); + { + let gpioa = unsafe { &*GPIOA::PTR }; + assert!(!is_pa8_low(gpioa)); + } + + pin.set_low().unwrap(); + delay.delay(1.millis()); // Give the pin plenty of time to go low + assert!(pin.is_low().unwrap()); + { + let gpioa = unsafe { &*GPIOA::PTR }; + assert!(is_pa8_low(gpioa)); + } + } + + #[test] + fn gpio_open_drain() { + use super::*; + + // TODO: Is it ok to steal these? + let cp = unsafe { stm32::CorePeripherals::steal() }; + let dp = unsafe { stm32::Peripherals::steal() }; + let mut rcc = dp.RCC.constrain(); + let mut delay = cp.SYST.delay(&rcc.clocks); + + let gpioa = dp.GPIOA.split(&mut rcc); + let mut pin = gpioa.pa8.into_open_drain_output(); + + // Enable pull-up resistor + { + let gpioa = unsafe { &*GPIOA::PTR }; + gpioa.pupdr().modify(|_, w| w.pupdr8().pull_up()); + } + + pin.set_high().unwrap(); + delay.delay(1.millis()); // Give the pin plenty of time to go high + assert!(pin.is_high().unwrap()); + { + let gpioa = unsafe { &*GPIOA::PTR }; + assert!(!is_pa8_low(gpioa)); + } + + pin.set_low().unwrap(); + delay.delay(1.millis()); // Give the pin plenty of time to go low + assert!(pin.is_low().unwrap()); + { + let gpioa = unsafe { &*GPIOA::PTR }; + assert!(is_pa8_low(gpioa)); + } + } + #[test] fn foo() { use super::*; - let cp = stm32::CorePeripherals::take().expect("cannot take peripherals"); - let dp = stm32::Peripherals::take().expect("cannot take peripherals"); + // TODO: Is it ok to steal these? + let cp = unsafe { stm32::CorePeripherals::steal() }; + let dp = unsafe { stm32::Peripherals::steal() }; let mut rcc = dp.RCC.constrain(); let mut delay = cp.SYST.delay(&rcc.clocks); let gpioa = dp.GPIOA.split(&mut rcc); - let pin: stm32g4xx_hal::gpio::gpioa::PA8> = gpioa.pa8.into_alternate(); + let pin: stm32g4xx_hal::gpio::gpioa::PA8> = + gpioa.pa8.into_alternate(); - //let mut pwm = dp.TIM1.pwm(pin, 1000u32.Hz(), &mut rcc); + let mut pwm = dp.TIM1.pwm(pin, 1000u32.Hz(), &mut rcc); - //pwm.set_duty_cycle_percent(50).unwrap(); - //pwm.enable(); - + pwm.set_duty_cycle_percent(50).unwrap(); + pwm.enable(); let gpioa = unsafe { &*GPIOA::PTR }; - let get_pin_state = || unsafe { (0x4800_0004 as *const u32).read_volatile() }; + //let get_pin_state = || unsafe { (0x4800_0004 as *const u32).read_volatile() }; // TODO: This is a very bad way to measure time - let min: MicrosDurationU32 = 490u32.micros();// Some extra on min for cpu overhead + let min: MicrosDurationU32 = 490u32.micros(); // Some extra on min for cpu overhead let max: MicrosDurationU32 = 505u32.micros(); { println!("Awaiting first rising edge..."); - //println!("{}", gpioa.odr().read().odr(8).is_high()); - println!("{}", get_pin_state()); - //let duration_until_lo = await_lo(&gpioa, &mut delay, max);//.unwrap(); - } - /* - //println!("Low..., Waited ~{}us until low", duration_until_lo); - let lo_duration = await_hi(&gpioa, &mut delay, max);//.unwrap(); - //println!("High..., Low half period: {}us", lo_duration); + let duration_until_lo = await_lo(&gpioa, &mut delay, max).unwrap(); + println!("Low..., Waited ~{} until low", duration_until_lo); + let lo_duration = await_hi(&gpioa, &mut delay, max).unwrap(); + println!("High..., Low half period: {}", lo_duration); } for _ in 0..10 { // Make sure the timer half periods are within 490-505us - let hi_duration = await_lo(&gpioa, &mut delay, max);//.unwrap(); - println!("Low..., High half period: {}us", hi_duration); - //assert!(hi_duration > min, "{} > {}", hi_duration, min); + let hi_duration = await_lo(&gpioa, &mut delay, max).unwrap(); + println!("Low..., High half period: {}", hi_duration); + assert!(hi_duration > min, "{} > {}", hi_duration, min); - let lo_duration = await_hi(&gpioa, &mut delay, max);//.unwrap(); - println!("High..., Low half period: {}us", lo_duration); - //assert!(lo_duration > min, "{} > {}", lo_duration, min); + let lo_duration = await_hi(&gpioa, &mut delay, max).unwrap(); + println!("High..., Low half period: {}", lo_duration); + assert!(lo_duration > min, "{} > {}", lo_duration, min); } println!("Done!"); for i in (0..5).rev() { println!("{}", i); delay.delay(1000.millis()); - }*/ + } + + pwm.disable(); } } +fn is_pa8_low(gpioa: &stm32::gpioa::RegisterBlock) -> bool { + gpioa.idr().read().idr(8).is_low() +} + #[derive(Debug, defmt::Format)] struct ErrorTimedOut; @@ -87,7 +163,7 @@ fn await_lo( delay: &mut SystDelay, timeout: MicrosDurationU32, ) -> Result { - await_p(|| gpioa.idr().read().idr(8).is_low(), delay, timeout) + await_p(|| is_pa8_low(gpioa), delay, timeout) } fn await_hi( @@ -95,7 +171,7 @@ fn await_hi( delay: &mut SystDelay, timeout: MicrosDurationU32, ) -> Result { - await_p(|| gpioa.idr().read().idr(8).is_high(), delay, timeout) + await_p(|| !is_pa8_low(gpioa), delay, timeout) } fn await_p( @@ -107,7 +183,7 @@ fn await_p( if p() { return Ok(i.micros()); } - //delay.delay(1_u32.micros()); + delay.delay(1_u32.micros()); } Err(ErrorTimedOut) } From b55172b6fe25e3ca06963e221c4cc980c25dc727 Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Thu, 30 Jan 2025 19:15:25 +0100 Subject: [PATCH 5/8] Rename things --- Cargo.toml | 4 ++-- tests/{pwm.rs => tests.rs} | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) rename tests/{pwm.rs => tests.rs} (99%) diff --git a/Cargo.toml b/Cargo.toml index c5a18498..f25d7b7a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -140,8 +140,8 @@ name = "cordic" required-features = ["cordic"] [[test]] -name = "pwm" +name = "tests" harness = false [lib] -test = false \ No newline at end of file +test = false diff --git a/tests/pwm.rs b/tests/tests.rs similarity index 99% rename from tests/pwm.rs rename to tests/tests.rs index 455d6fe2..1f45d8f5 100644 --- a/tests/pwm.rs +++ b/tests/tests.rs @@ -95,7 +95,7 @@ mod tests { } #[test] - fn foo() { + fn pwm() { use super::*; // TODO: Is it ok to steal these? From 57a6dcf15ac7d7c47ac76dcbdee68f8947044bad Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Sun, 30 Mar 2025 03:04:26 +0200 Subject: [PATCH 6/8] Add more tests --- tests/tests.rs | 233 ++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 190 insertions(+), 43 deletions(-) diff --git a/tests/tests.rs b/tests/tests.rs index 1f45d8f5..89cc024d 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -4,27 +4,51 @@ #[path = "../examples/utils/mod.rs"] mod utils; -use utils::logger::println; +use utils::logger::debug; use core::ops::FnMut; use core::result::Result; -use fugit::{ExtU32, MicrosDurationU32}; -use hal::delay::{DelayExt, SystDelay}; +use fugit::{ExtU32, HertzU32, MicrosDurationU32}; +use hal::delay::DelayExt; use hal::stm32; use stm32g4xx_hal as hal; +pub const F_SYS: HertzU32 = HertzU32::MHz(16); +pub const CYCLES_PER_US: u32 = F_SYS.raw() / 1_000_000; + +pub fn enable_timer(cp: &mut stm32::CorePeripherals) { + cp.DCB.enable_trace(); + cp.DWT.enable_cycle_counter(); +} + +pub fn now() -> MicrosDurationU32 { + (stm32::DWT::cycle_count() / CYCLES_PER_US).micros() +} + #[defmt_test::tests] mod tests { use embedded_hal::{ + delay::DelayNs, digital::{InputPin, OutputPin}, pwm::SetDutyCycle, }; + use fixed::types::I1F15; use fugit::RateExtU32; use stm32g4xx_hal::{ + adc::{self, AdcClaim, Temperature, Vref}, + cordic::{ + op::{dynamic::Mode, Magnitude, SinCos, Sqrt}, + prec::P60, + scale::N0, + types::{Q15, Q31}, + Ext, + }, + dac::{DacExt, DacOut}, delay::SYSTDelayExt, gpio::{GpioExt, AF6}, pwm::PwmExt, rcc::RccExt, + signature::{VrefCal, VDDA_CALIB}, stm32::GPIOA, }; @@ -37,6 +61,7 @@ mod tests { let dp = unsafe { stm32::Peripherals::steal() }; let mut rcc = dp.RCC.constrain(); let mut delay = cp.SYST.delay(&rcc.clocks); + defmt::dbg!(rcc.clocks.sys_clk); let gpioa = dp.GPIOA.split(&mut rcc); let mut pin = gpioa.pa8.into_push_pull_output(); @@ -46,7 +71,7 @@ mod tests { assert!(pin.is_high().unwrap()); { let gpioa = unsafe { &*GPIOA::PTR }; - assert!(!is_pa8_low(gpioa)); + assert!(!is_pax_low(gpioa, 8)); } pin.set_low().unwrap(); @@ -54,7 +79,7 @@ mod tests { assert!(pin.is_low().unwrap()); { let gpioa = unsafe { &*GPIOA::PTR }; - assert!(is_pa8_low(gpioa)); + assert!(is_pax_low(gpioa, 8)); } } @@ -82,7 +107,7 @@ mod tests { assert!(pin.is_high().unwrap()); { let gpioa = unsafe { &*GPIOA::PTR }; - assert!(!is_pa8_low(gpioa)); + assert!(!is_pax_low(gpioa, 8)); } pin.set_low().unwrap(); @@ -90,7 +115,7 @@ mod tests { assert!(pin.is_low().unwrap()); { let gpioa = unsafe { &*GPIOA::PTR }; - assert!(is_pa8_low(gpioa)); + assert!(is_pax_low(gpioa, 8)); } } @@ -99,10 +124,12 @@ mod tests { use super::*; // TODO: Is it ok to steal these? - let cp = unsafe { stm32::CorePeripherals::steal() }; + let mut cp = unsafe { stm32::CorePeripherals::steal() }; let dp = unsafe { stm32::Peripherals::steal() }; + enable_timer(&mut cp); + let mut rcc = dp.RCC.constrain(); - let mut delay = cp.SYST.delay(&rcc.clocks); + assert_eq!(rcc.clocks.sys_clk, F_SYS); let gpioa = dp.GPIOA.split(&mut rcc); let pin: stm32g4xx_hal::gpio::gpioa::PA8> = @@ -115,44 +142,163 @@ mod tests { let gpioa = unsafe { &*GPIOA::PTR }; - //let get_pin_state = || unsafe { (0x4800_0004 as *const u32).read_volatile() }; - - // TODO: This is a very bad way to measure time - let min: MicrosDurationU32 = 490u32.micros(); // Some extra on min for cpu overhead + let min: MicrosDurationU32 = 495u32.micros(); let max: MicrosDurationU32 = 505u32.micros(); - { - println!("Awaiting first rising edge..."); - let duration_until_lo = await_lo(&gpioa, &mut delay, max).unwrap(); - println!("Low..., Waited ~{} until low", duration_until_lo); - let lo_duration = await_hi(&gpioa, &mut delay, max).unwrap(); - println!("High..., Low half period: {}", lo_duration); - } + debug!("Awaiting first rising edge..."); + let duration_until_lo = await_lo(&gpioa, max).unwrap(); + let first_lo_duration = await_hi(&gpioa, max).unwrap(); + + let mut hi_duration = 0.micros(); + let mut lo_duration = 0.micros(); for _ in 0..10 { - // Make sure the timer half periods are within 490-505us + // Make sure the timer half periods are within 495-505us + + hi_duration = await_lo(&gpioa, max).unwrap(); + assert!( + hi_duration > min && hi_duration < max, + "hi: {} < {} < {}", + min, + hi_duration, + max + ); + + lo_duration = await_hi(&gpioa, max).unwrap(); + assert!( + lo_duration > min && lo_duration < max, + "lo: {} < {} < {}", + min, + lo_duration, + max + ); + } + + // Prints deferred until here to not mess up timing + debug!("Waited ~{} until low", duration_until_lo); + debug!("First low half period: {}", first_lo_duration); - let hi_duration = await_lo(&gpioa, &mut delay, max).unwrap(); - println!("Low..., High half period: {}", hi_duration); - assert!(hi_duration > min, "{} > {}", hi_duration, min); + debug!("High half period: {}", hi_duration); + debug!("Low half period: {}", lo_duration); - let lo_duration = await_hi(&gpioa, &mut delay, max).unwrap(); - println!("High..., Low half period: {}", lo_duration); - assert!(lo_duration > min, "{} > {}", lo_duration, min); + debug!("Done!"); + + pwm.disable(); + } + + #[test] + fn cordic() { + fn is_almost_equals(a: f32, b: f32) -> bool { + (a - b).abs() < 0.001 } - println!("Done!"); - for i in (0..5).rev() { - println!("{}", i); - delay.delay(1000.millis()); + use super::*; + + let dp = unsafe { stm32::Peripherals::steal() }; + let mut rcc = dp.RCC.constrain(); + + let mut cordic = dp + .CORDIC + .constrain(&mut rcc) + .freeze::(); // 16 bit arguments, 32 bit results, compute sine and cosine, 60 iterations + + // static operation (zero overhead) + + cordic.start(I1F15::from_num(-0.25 /* -45 degreees */)); + + let (sin, cos) = cordic.result(); + + debug!("sin: {}, cos: {}", sin.to_num::(), cos.to_num::()); + assert!(is_almost_equals(sin.to_num::(), -0.707)); + assert!(is_almost_equals(cos.to_num::(), 0.707)); + + // dynamic operation + + let mut cordic = cordic.into_dynamic(); + + let sqrt = cordic.run::>(I1F15::from_num(0.25)); + debug!("sqrt: {}", sqrt.to_num::()); + assert!(is_almost_equals(sqrt.to_num::(), 0.5)); + let magnitude = cordic.run::((I1F15::from_num(0.25), I1F15::from_num(0.5))); + debug!("magnitude: {}", magnitude.to_num::()); + assert!(is_almost_equals(magnitude.to_num::(), 0.559)); + } + + #[test] + fn adc() { + use super::*; + + // TODO: Is it ok to steal these? + let cp = unsafe { stm32::CorePeripherals::steal() }; + let dp = unsafe { stm32::Peripherals::steal() }; + let rcc = dp.RCC.constrain(); + let mut delay = cp.SYST.delay(&rcc.clocks); + + let mut adc = dp + .ADC1 + .claim(adc::ClockSource::SystemClock, &rcc, &mut delay, true); + + adc.enable_temperature(&dp.ADC12_COMMON); + adc.enable_vref(&dp.ADC12_COMMON); + let sample_time = adc::config::SampleTime::Cycles_640_5; + + let vref = adc.convert(&Vref, sample_time); + let vref_cal = VrefCal::get().read(); + let vdda = VDDA_CALIB * vref_cal as u32 / vref as u32; + debug!("vdda: {}mV", vdda); + assert!((3200..3400).contains(&vdda)); + + let vref = Vref::sample_to_millivolts_ext(vref, vdda, adc::config::Resolution::Twelve); + debug!("vref: {}mV", vref); + assert!((1182..1232).contains(&vref)); // From G474 datasheet + + let temperature_reading = adc.convert(&Temperature, sample_time); + let temp = Temperature::temperature_to_degrees_centigrade( + temperature_reading, + vdda as f32 / 1000., + adc::config::Resolution::Twelve, + ); + debug!("temp: {}°C", temp); + assert!((20.0..30.0).contains(&temp), "20.0 < {} < 30.0", temp); + } + + // TODO: This does not seem to work + #[test] + fn dac() { + use super::*; + + // TODO: Is it ok to steal these? + let cp = unsafe { stm32::CorePeripherals::steal() }; + let dp = unsafe { stm32::Peripherals::steal() }; + let mut rcc = dp.RCC.constrain(); + let mut delay = cp.SYST.delay(&rcc.clocks); + + let gpioa = dp.GPIOA.split(&mut rcc); + let dac1ch1 = dp.DAC1.constrain(gpioa.pa4, &mut rcc); + + let gpioa = unsafe { &*GPIOA::PTR }; + + // dac_manual will have its value set manually + let mut dac = dac1ch1.calibrate_buffer(&mut delay).enable(); + + dac.set_value(0); + delay.delay_ms(100); + assert!(is_pax_low(&gpioa, 4)); + + /*for i in (0..=4095).step_by(10) { + dac.set_value(i); + delay.delay_ms(1); + defmt::println!("i: {}, is_pax_low: {}", i, gpioa.idr().read().bits()); } - pwm.disable(); + delay.delay_ms(100); + assert!(!is_pax_low(&gpioa, 4)); // TODO: <---- Why does this not work? + */ } } -fn is_pa8_low(gpioa: &stm32::gpioa::RegisterBlock) -> bool { - gpioa.idr().read().idr(8).is_low() +fn is_pax_low(gpioa: &stm32::gpioa::RegisterBlock, x: u8) -> bool { + gpioa.idr().read().idr(x).is_low() } #[derive(Debug, defmt::Format)] @@ -160,30 +306,31 @@ struct ErrorTimedOut; fn await_lo( gpioa: &stm32::gpioa::RegisterBlock, - delay: &mut SystDelay, timeout: MicrosDurationU32, ) -> Result { - await_p(|| is_pa8_low(gpioa), delay, timeout) + await_p(|| is_pax_low(gpioa, 8), timeout) } fn await_hi( gpioa: &stm32::gpioa::RegisterBlock, - delay: &mut SystDelay, timeout: MicrosDurationU32, ) -> Result { - await_p(|| !is_pa8_low(gpioa), delay, timeout) + await_p(|| !is_pax_low(gpioa, 8), timeout) } fn await_p( mut p: impl FnMut() -> bool, - delay: &mut SystDelay, timeout: MicrosDurationU32, ) -> Result { - for i in 0..timeout.ticks() { + let before = now(); + + loop { + let passed_time = now() - before; if p() { - return Ok(i.micros()); + return Ok(passed_time); + } + if passed_time > timeout { + return Err(ErrorTimedOut); } - delay.delay(1_u32.micros()); } - Err(ErrorTimedOut) } From 932d5507f3c8a5bc0e7d70e7964db8fe24d7e576 Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Sun, 30 Mar 2025 19:57:57 +0200 Subject: [PATCH 7/8] Fix DAC test --- tests/tests.rs | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/tests/tests.rs b/tests/tests.rs index 89cc024d..1666fcad 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -261,8 +261,7 @@ mod tests { debug!("temp: {}°C", temp); assert!((20.0..30.0).contains(&temp), "20.0 < {} < 30.0", temp); } - - // TODO: This does not seem to work + #[test] fn dac() { use super::*; @@ -274,7 +273,8 @@ mod tests { let mut delay = cp.SYST.delay(&rcc.clocks); let gpioa = dp.GPIOA.split(&mut rcc); - let dac1ch1 = dp.DAC1.constrain(gpioa.pa4, &mut rcc); + let pa4 = gpioa.pa4.into_floating_input(); + let dac1ch1 = dp.DAC1.constrain(pa4, &mut rcc); let gpioa = unsafe { &*GPIOA::PTR }; @@ -282,18 +282,12 @@ mod tests { let mut dac = dac1ch1.calibrate_buffer(&mut delay).enable(); dac.set_value(0); - delay.delay_ms(100); + delay.delay_ms(1); assert!(is_pax_low(&gpioa, 4)); - /*for i in (0..=4095).step_by(10) { - dac.set_value(i); - delay.delay_ms(1); - defmt::println!("i: {}, is_pax_low: {}", i, gpioa.idr().read().bits()); - } - - delay.delay_ms(100); - assert!(!is_pax_low(&gpioa, 4)); // TODO: <---- Why does this not work? - */ + dac.set_value(4095); + delay.delay_ms(1); + assert!(!is_pax_low(&gpioa, 4)); } } From bbf7232abba43b42604edd719748447e289d74e4 Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Sun, 30 Mar 2025 19:59:53 +0200 Subject: [PATCH 8/8] fmt --- tests/tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/tests.rs b/tests/tests.rs index 1666fcad..3d158013 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -261,7 +261,7 @@ mod tests { debug!("temp: {}°C", temp); assert!((20.0..30.0).contains(&temp), "20.0 < {} < 30.0", temp); } - + #[test] fn dac() { use super::*;