From 1ad4d91f3e546ea42fc8373797e5d74a139ed7af Mon Sep 17 00:00:00 2001 From: Richard Meadows <962920+richardeoin@users.noreply.github.com> Date: Thu, 21 Dec 2023 17:53:36 +0100 Subject: [PATCH 01/13] Update to embedded-hal v1.0.0 general changes --- CHANGELOG.md | 4 ++++ Cargo.toml | 2 +- src/prelude.rs | 1 - 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 30893f4a..2b786d39 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,10 @@ ## [Unreleased] * MSRV increased to Rust 1.66.1 [#473] +* Upgraded to embedded-hal v1.0.0-rc.3 + +* pwm: Renamed `get_max_duty` -> `max_duty_cycle`; `set_duty` -> `set_duty_cycle` +* pwm: `enable` method now returns type `Result<(), PwmError>` ## [v0.15.1] 2023-11-03 diff --git a/Cargo.toml b/Cargo.toml index b8a8c9cf..6f36f262 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,7 +28,7 @@ rustdoc-args = ["--cfg", "docsrs"] [dependencies] fugit = "0.3.5" -embedded-hal = { version = "0.2.6", features = ["unproven"] } +embedded-hal = { version = "=1.0.0-rc.3" } embedded-dma = "0.2.0" cortex-m = { version = "^0.7.7", features = ["critical-section-single-core"] } defmt = { version = ">=0.2.0,<0.4", optional = true } diff --git a/src/prelude.rs b/src/prelude.rs index d873702c..2d5fcac0 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -1,5 +1,4 @@ //! Prelude -pub use embedded_hal::prelude::*; pub use crate::adc::AdcExt as _stm32h7xx_hal_adc_AdcExt; #[cfg(feature = "can")] From d29462a0559ca15e0cbcefe5a004b505dfe3abe3 Mon Sep 17 00:00:00 2001 From: Richard Meadows <962920+richardeoin@users.noreply.github.com> Date: Thu, 21 Dec 2023 18:01:24 +0100 Subject: [PATCH 02/13] eh-1.0.0: adc and dac --- examples/dac.rs | 2 +- examples/temperature.rs | 3 ++- src/adc.rs | 46 +++++++++++++++++++++-------------------- src/dac.rs | 6 +++--- 4 files changed, 30 insertions(+), 27 deletions(-) diff --git a/examples/dac.rs b/examples/dac.rs index ff5583b9..42daf69d 100644 --- a/examples/dac.rs +++ b/examples/dac.rs @@ -4,7 +4,7 @@ use cortex_m::asm; use cortex_m_rt::entry; -use stm32h7xx_hal::hal::Direction; +use stm32h7xx_hal::qei::Direction; #[macro_use] mod utilities; use stm32h7xx_hal::{pac, prelude::*}; diff --git a/examples/temperature.rs b/examples/temperature.rs index 1684a4ae..1245f434 100644 --- a/examples/temperature.rs +++ b/examples/temperature.rs @@ -11,6 +11,7 @@ use cortex_m_rt::entry; #[macro_use] mod utilities; +use embedded_hal::delay::DelayNs; use stm32h7xx_hal::{ adc, delay::Delay, @@ -73,7 +74,7 @@ fn main() -> ! { // Setup Temperature Sensor on the disabled ADC let mut channel = adc::Temperature::new(); channel.enable(&adc); - delay.delay_us(25_u16); + delay.delay_us(25); let mut adc = adc.enable(); let vdda = 2.500; // Volts diff --git a/src/adc.rs b/src/adc.rs index 2acb56f1..0ce9bffd 100644 --- a/src/adc.rs +++ b/src/adc.rs @@ -11,8 +11,7 @@ //! - [Using ADC1 and ADC2 in parallel](https://github.com/stm32-rs/stm32h7xx-hal/blob/master/examples/adc12_parallel.rs) //! - [Using ADC1 through DMA](https://github.com/stm32-rs/stm32h7xx-hal/blob/master/examples/adc_dma.rs) -use crate::hal::adc::{Channel, OneShot}; -use crate::hal::blocking::delay::DelayUs; +use crate::hal::delay::DelayNs; use core::convert::Infallible; use core::marker::PhantomData; @@ -186,6 +185,11 @@ impl AdcCalLinear { } } +/// A marker trait to identify MCU pins that can be used as inputs to an ADC channel +pub trait Channel { + type ID; + fn channel() -> Self::ID; +} macro_rules! adc_pins { ($ADC:ident, $($input:ty => $chan:expr),+ $(,)*) => { $( @@ -364,7 +368,7 @@ pub trait AdcExt: Sized { fn adc( self, f_adc: impl Into, - delay: &mut impl DelayUs, + delay: &mut impl DelayNs, prec: Self::Rec, clocks: &CoreClocks, ) -> Adc; @@ -421,7 +425,7 @@ pub fn adc12( adc1: ADC1, adc2: ADC2, f_adc: impl Into, - delay: &mut impl DelayUs, + delay: &mut impl DelayNs, prec: rec::Adc12, clocks: &CoreClocks, ) -> (Adc, Adc) { @@ -500,7 +504,7 @@ macro_rules! adc_hal { fn adc(self, f_adc: impl Into, - delay: &mut impl DelayUs, + delay: &mut impl DelayNs, prec: rec::$Rec, clocks: &CoreClocks) -> Adc<$ADC, Disabled> { @@ -513,7 +517,7 @@ macro_rules! adc_hal { /// /// Sets all configurable parameters to one-shot defaults, /// performs a boot-time calibration. - pub fn $adcX(adc: $ADC, f_adc: impl Into, delay: &mut impl DelayUs, + pub fn $adcX(adc: $ADC, f_adc: impl Into, delay: &mut impl DelayNs, prec: rec::$Rec, clocks: &CoreClocks ) -> Self { // Consume ADC register block, produce Self with default @@ -631,13 +635,14 @@ macro_rules! adc_hal { /// Disables Deeppowerdown-mode and enables voltage regulator /// /// Note: After power-up, a [`calibration`](#method.calibrate) shall be run - pub fn power_up(&mut self, delay: &mut impl DelayUs) { + pub fn power_up(&mut self, delay: &mut impl DelayNs) { // Refer to RM0433 Rev 7 - Chapter 25.4.6 self.rb.cr.modify(|_, w| w.deeppwd().clear_bit() .advregen().set_bit() ); - delay.delay_us(10_u8); + + delay.delay_us(10); // check LDORDY bit if present $( @@ -884,6 +889,17 @@ macro_rules! adc_hal { nb::Result::Ok(result) } + /// Perform an ADC conversion on the specified pin + pub fn read(&mut self, pin: &mut PIN) -> nb::Result + where + PIN: Channel<$ADC, ID = u8>, + T: From + { + self.start_conversion(pin); + let res = block!(self.read_sample()).unwrap(); + Ok(res.into()) + } + fn check_conversion_conditions(&self) { let cr = self.rb.cr.read(); // Ensure that no conversions are ongoing @@ -1111,20 +1127,6 @@ macro_rules! adc_hal { &mut self.rb } } - - impl OneShot<$ADC, WORD, PIN> for Adc<$ADC, Enabled> - where - WORD: From, - PIN: Channel<$ADC, ID = u8>, - { - type Error = (); - - fn read(&mut self, pin: &mut PIN) -> nb::Result { - self.start_conversion(pin); - let res = block!(self.read_sample()).unwrap(); - Ok(res.into()) - } - } )+ } } diff --git a/src/dac.rs b/src/dac.rs index 0617739b..72e563c9 100644 --- a/src/dac.rs +++ b/src/dac.rs @@ -9,7 +9,7 @@ use core::marker::PhantomData; use core::mem::MaybeUninit; use crate::gpio::{self, Analog}; -use crate::hal::blocking::delay::DelayUs; +use crate::hal::delay::DelayNs; use crate::rcc::{rec, ResetEnable}; #[cfg(not(feature = "rm0455"))] use crate::stm32::DAC as DAC1; @@ -127,7 +127,7 @@ macro_rules! dac { delay: &mut T, ) -> $CX<$DAC, Disabled> where - T: DelayUs, + T: DelayNs, { let dac = unsafe { &(*$DAC::ptr()) }; dac.cr.modify(|_, w| w.$en().clear_bit()); @@ -136,7 +136,7 @@ macro_rules! dac { let mut trim = 0; while true { dac.ccr.modify(|_, w| unsafe { w.$trim().bits(trim) }); - delay.delay_us(64_u32); + delay.delay_us(64); if dac.sr.read().$cal_flag().bit() { break; } From cee3c76907d64889dea2e8c3346af9647b55755e Mon Sep 17 00:00:00 2001 From: Richard Meadows <962920+richardeoin@users.noreply.github.com> Date: Thu, 21 Dec 2023 18:05:37 +0100 Subject: [PATCH 03/13] eh-1.0.0: gpio --- examples/blinky.rs | 11 +- examples/blinky_random.rs | 1 + examples/blinky_timer.rs | 10 +- examples/gpio_with_input.rs | 6 +- src/gpio.rs | 4 +- src/gpio/hal_02.rs | 27 ++++- src/gpio/hal_1.rs | 228 ++++++++++++++++++++++++++++++++++++ 7 files changed, 266 insertions(+), 21 deletions(-) create mode 100644 src/gpio/hal_1.rs diff --git a/examples/blinky.rs b/examples/blinky.rs index 4ce8f973..7a2497aa 100644 --- a/examples/blinky.rs +++ b/examples/blinky.rs @@ -5,13 +5,14 @@ #![no_std] use cortex_m_rt::entry; +#[macro_use] +mod utilities; + +use embedded_hal::delay::DelayNs; use stm32h7xx_hal::{pac, prelude::*}; use log::info; -#[macro_use] -mod utilities; - #[entry] fn main() -> ! { utilities::logger::init(); @@ -42,9 +43,9 @@ fn main() -> ! { loop { led.set_high(); - delay.delay_ms(500_u16); + delay.delay_ms(500); led.set_low(); - delay.delay_ms(500_u16); + delay.delay_ms(500); } } diff --git a/examples/blinky_random.rs b/examples/blinky_random.rs index d9129016..c1828473 100644 --- a/examples/blinky_random.rs +++ b/examples/blinky_random.rs @@ -7,6 +7,7 @@ #![no_std] use cortex_m_rt::entry; +use embedded_hal::delay::DelayNs; use stm32h7xx_hal::{pac, prelude::*}; #[macro_use] diff --git a/examples/blinky_timer.rs b/examples/blinky_timer.rs index 89cfd543..ac6cf0c2 100644 --- a/examples/blinky_timer.rs +++ b/examples/blinky_timer.rs @@ -10,7 +10,8 @@ mod utilities; extern crate nb; use cortex_m_rt::entry; -use stm32h7xx_hal::{pac, prelude::*, time::MilliSeconds}; +use embedded_hal::delay::DelayNs; +use stm32h7xx_hal::{pac, prelude::*}; use log::info; @@ -50,13 +51,12 @@ fn main() -> ! { for _ in 0..5 { // 20ms wait with timer led.toggle(); - timer.start(MilliSeconds::from_ticks(20).into_rate()); + timer.start(50.Hz()).unwrap(); block!(timer.wait()).ok(); - // Delay for 500ms. Timer must operate correctly on next - // use. + // Delay for 500ms. Timer must operate correctly on next use. led.toggle(); - delay.delay_ms(500_u16); + delay.delay_ms(500); } } } diff --git a/examples/gpio_with_input.rs b/examples/gpio_with_input.rs index 3273d3d3..994dd7ed 100644 --- a/examples/gpio_with_input.rs +++ b/examples/gpio_with_input.rs @@ -7,7 +7,7 @@ #![no_std] use cortex_m_rt::entry; - +use embedded_hal::delay::DelayNs; use stm32h7xx_hal::{pac, prelude::*}; use log::info; @@ -45,10 +45,10 @@ fn main() -> ! { loop { led.set_high(); - delay.delay_ms(100_u16); + delay.delay_ms(100); led.set_low(); - delay.delay_ms(100_u16); + delay.delay_ms(100); let is_high = led.with_input(|x| x.is_high()); info!("LED pin high? {}", is_high); diff --git a/src/gpio.rs b/src/gpio.rs index 3419e22c..e4d18db2 100644 --- a/src/gpio.rs +++ b/src/gpio.rs @@ -76,8 +76,9 @@ pub use exti::ExtiPin; mod dynamic; pub use dynamic::{Dynamic, DynamicPin}; mod hal_02; +mod hal_1; -pub use embedded_hal::digital::v2::PinState; +pub use embedded_hal::digital::PinState; use core::fmt; @@ -458,7 +459,6 @@ impl Pin> { pub fn set_low(&mut self) { self._set_low() } - /// Is the pin in drive high or low mode? #[inline(always)] pub fn get_state(&self) -> PinState { diff --git a/src/gpio/hal_02.rs b/src/gpio/hal_02.rs index f8d62f69..73618ef3 100644 --- a/src/gpio/hal_02.rs +++ b/src/gpio/hal_02.rs @@ -2,13 +2,28 @@ use core::convert::Infallible; use super::{ dynamic::PinModeError, marker, DynamicPin, ErasedPin, Input, OpenDrain, - Output, PartiallyErasedPin, Pin, PinMode, PinState, + Output, PartiallyErasedPin, Pin, PinMode, }; -use embedded_hal::digital::v2::{ - InputPin, IoPin, OutputPin, StatefulOutputPin, ToggleableOutputPin, +use embedded_hal_02::digital::v2::{ + InputPin, IoPin, OutputPin, PinState, StatefulOutputPin, + ToggleableOutputPin, }; +impl Pin { + /// Set the output of the pin regardless of its mode. + /// Primarily used to set the output value of the pin + /// before changing its mode to an output to avoid + /// a short spike of an incorrect value + #[inline(always)] + fn _set_state_02(&mut self, state: PinState) { + match state { + PinState::High => self._set_high(), + PinState::Low => self._set_low(), + } + } +} + // Implementations for `Pin` impl OutputPin for Pin> { @@ -78,7 +93,7 @@ impl IoPin Ok(self) } fn into_output_pin(mut self, state: PinState) -> Result { - self.set_state(state); + self._set_state_02(state); Ok(self) } } @@ -93,7 +108,7 @@ where Ok(self.into_input()) } fn into_output_pin(mut self, state: PinState) -> Result { - self.set_state(state); + self._set_state_02(state); Ok(self) } } @@ -111,7 +126,7 @@ where mut self, state: PinState, ) -> Result>, Self::Error> { - self._set_state(state); + self._set_state_02(state); Ok(self.into_mode()) } } diff --git a/src/gpio/hal_1.rs b/src/gpio/hal_1.rs new file mode 100644 index 00000000..b0011117 --- /dev/null +++ b/src/gpio/hal_1.rs @@ -0,0 +1,228 @@ +use super::{ + dynamic::PinModeError, marker, DynamicPin, ErasedPin, Output, + PartiallyErasedPin, Pin, +}; + +use embedded_hal::digital::{ErrorKind, ErrorType}; +use embedded_hal::digital::{ + InputPin, OutputPin, StatefulOutputPin, ToggleableOutputPin, +}; + +/// Error type for GPIO +#[derive(Clone, Copy, Debug, PartialEq)] +#[non_exhaustive] +pub enum GpioError { + /// [DynamicPin] For operations unsupported in current mode + IncorrectMode, + /// Error + Other, +} +impl embedded_hal::digital::Error for GpioError { + fn kind(&self) -> ErrorKind { + ErrorKind::Other + } +} +impl From for GpioError { + fn from(_: PinModeError) -> GpioError { + GpioError::IncorrectMode + } +} + +// Implementations for `Pin` + +impl ErrorType for Pin { + type Error = GpioError; +} + +impl OutputPin for Pin> { + #[inline(always)] + fn set_high(&mut self) -> Result<(), Self::Error> { + self.set_high(); + Ok(()) + } + + #[inline(always)] + fn set_low(&mut self) -> Result<(), Self::Error> { + self.set_low(); + Ok(()) + } +} + +impl StatefulOutputPin + for Pin> +{ + #[inline(always)] + fn is_set_high(&mut self) -> Result { + Ok(!self._is_set_low()) + } + + #[inline(always)] + fn is_set_low(&mut self) -> Result { + Ok(self._is_set_low()) + } +} + +impl ToggleableOutputPin + for Pin> +{ + #[inline(always)] + fn toggle(&mut self) -> Result<(), Self::Error> { + self.toggle(); + Ok(()) + } +} + +impl InputPin for Pin +where + MODE: marker::Readable, +{ + #[inline(always)] + fn is_high(&mut self) -> Result { + Ok(!self._is_low()) + } + + #[inline(always)] + fn is_low(&mut self) -> Result { + Ok(self._is_low()) + } +} + +// Implementations for `ErasedPin` + +impl ErrorType for ErasedPin { + type Error = GpioError; +} + +impl OutputPin for ErasedPin> { + #[inline(always)] + fn set_high(&mut self) -> Result<(), Self::Error> { + self.set_high(); + Ok(()) + } + + #[inline(always)] + fn set_low(&mut self) -> Result<(), Self::Error> { + self.set_low(); + Ok(()) + } +} + +impl StatefulOutputPin for ErasedPin> { + #[inline(always)] + fn is_set_high(&mut self) -> Result { + Ok(ErasedPin::is_set_high(self)) + } + + #[inline(always)] + fn is_set_low(&mut self) -> Result { + Ok(ErasedPin::is_set_low(self)) + } +} + +impl ToggleableOutputPin for ErasedPin> { + #[inline(always)] + fn toggle(&mut self) -> Result<(), Self::Error> { + self.toggle(); + Ok(()) + } +} + +impl InputPin for ErasedPin +where + MODE: marker::Readable, +{ + #[inline(always)] + fn is_high(&mut self) -> Result { + Ok(ErasedPin::is_high(self)) + } + + #[inline(always)] + fn is_low(&mut self) -> Result { + Ok(ErasedPin::is_low(self)) + } +} + +// Implementations for `PartiallyErasedPin` + +impl ErrorType for PartiallyErasedPin { + type Error = GpioError; +} + +impl OutputPin for PartiallyErasedPin> { + #[inline(always)] + fn set_high(&mut self) -> Result<(), Self::Error> { + self.set_high(); + Ok(()) + } + + #[inline(always)] + fn set_low(&mut self) -> Result<(), Self::Error> { + self.set_low(); + Ok(()) + } +} + +impl StatefulOutputPin + for PartiallyErasedPin> +{ + #[inline(always)] + fn is_set_high(&mut self) -> Result { + Ok(PartiallyErasedPin::is_set_high(self)) + } + + #[inline(always)] + fn is_set_low(&mut self) -> Result { + Ok(PartiallyErasedPin::is_set_low(self)) + } +} + +impl ToggleableOutputPin + for PartiallyErasedPin> +{ + #[inline(always)] + fn toggle(&mut self) -> Result<(), Self::Error> { + self.toggle(); + Ok(()) + } +} + +impl InputPin for PartiallyErasedPin +where + MODE: marker::Readable, +{ + #[inline(always)] + fn is_high(&mut self) -> Result { + Ok(PartiallyErasedPin::is_high(self)) + } + + #[inline(always)] + fn is_low(&mut self) -> Result { + Ok(PartiallyErasedPin::is_low(self)) + } +} + +// Implementations for `DynamicPin` + +impl ErrorType for DynamicPin { + type Error = GpioError; +} + +impl OutputPin for DynamicPin { + fn set_high(&mut self) -> Result<(), Self::Error> { + self.set_high()?; + Ok(()) + } + fn set_low(&mut self) -> Result<(), Self::Error> { + self.set_low()?; + Ok(()) + } +} + +impl InputPin for DynamicPin { + fn is_high(&mut self) -> Result { + Ok(DynamicPin::is_high(self)?) + } + fn is_low(&mut self) -> Result { + Ok(DynamicPin::is_low(self)?) + } +} From 239f7aea34c8f0ba71019a89e8dbdf23839c241f Mon Sep 17 00:00:00 2001 From: Richard Meadows <962920+richardeoin@users.noreply.github.com> Date: Thu, 21 Dec 2023 18:06:51 +0100 Subject: [PATCH 04/13] eh-1.0.0: timers and delays --- CHANGELOG.md | 2 + examples/can-echo.rs | 3 +- examples/can-fd.rs | 3 +- examples/embedded-graphics.rs | 3 +- examples/reset_reason.rs | 4 +- examples/sdmmc.rs | 3 +- examples/sdmmc_fat.rs | 1 + examples/usb_phy_serial_interrupt.rs | 9 +- src/delay.rs | 197 +++++++++++---------------- src/pwm.rs | 18 ++- src/system_watchdog.rs | 12 +- src/timer.rs | 30 ++-- 12 files changed, 133 insertions(+), 152 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2b786d39..a3581d50 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ * MSRV increased to Rust 1.66.1 [#473] * Upgraded to embedded-hal v1.0.0-rc.3 +* delay: `delay_ms` and 'delay_us` methods now require importing: `use embedded_hal::delay::DelayNs;` + * pwm: Renamed `get_max_duty` -> `max_duty_cycle`; `set_duty` -> `set_duty_cycle` * pwm: `enable` method now returns type `Result<(), PwmError>` diff --git a/examples/can-echo.rs b/examples/can-echo.rs index 83d8650c..a6c56168 100644 --- a/examples/can-echo.rs +++ b/examples/can-echo.rs @@ -18,6 +18,7 @@ use crate::hal::{ rcc, rcc::rec, }; +use embedded_hal::delay::DelayNs; use fdcan::{ config::NominalBitTiming, filter::{StandardFilter, StandardFilterSlot}, @@ -135,7 +136,7 @@ fn main() -> ! { info!("Received Header: {:#X?}", rxheader); info!("received data: {:X?}", &buffer); - delay.delay_ms(1_u16); + delay.delay_ms(1); block!(can.transmit(rxheader.unwrap().to_tx_header(None), &buffer)) .unwrap(); info!("Transmit: {:X?}", buffer); diff --git a/examples/can-fd.rs b/examples/can-fd.rs index ddfa0810..b57a8021 100644 --- a/examples/can-fd.rs +++ b/examples/can-fd.rs @@ -30,6 +30,7 @@ use crate::hal::{ rcc, rcc::rec, }; +use embedded_hal::delay::DelayNs; use fdcan::{ config::{DataBitTiming, FrameTransmissionConfig, NominalBitTiming}, filter::{StandardFilter, StandardFilterSlot}, @@ -167,7 +168,7 @@ fn main() -> ! { info!("Received Header: {:#X?}", rxheader); info!("received data: {:X?}", &buffer); - delay.delay_ms(1_u16); + delay.delay_ms(1); block!(can.transmit(rxheader.unwrap().to_tx_header(None), &buffer)) .unwrap(); info!("Transmit: {:X?}", buffer); diff --git a/examples/embedded-graphics.rs b/examples/embedded-graphics.rs index cbdc2386..41659af3 100644 --- a/examples/embedded-graphics.rs +++ b/examples/embedded-graphics.rs @@ -21,6 +21,7 @@ extern crate cortex_m_rt as rt; use core::sync::atomic::{AtomicU32, Ordering}; use cortex_m_rt::{entry, exception}; +use embedded_hal::delay::DelayNs; use stm32h7xx_hal::gpio::Speed; use stm32h7xx_hal::rcc::CoreClocks; use stm32h7xx_hal::{ltdc, xspi}; @@ -205,7 +206,7 @@ fn main() -> ! { let mut lcd_disp_ctrl = gpiod.pd10.into_push_pull_output(); let mut lcd_bl_ctrl = gpiog.pg15.into_push_pull_output(); - delay.delay_ms(40u8); + delay.delay_ms(40); let mut ltdc = ltdc::Ltdc::new(dp.LTDC, ccdr.peripheral.LTDC, &ccdr.clocks); diff --git a/examples/reset_reason.rs b/examples/reset_reason.rs index 12b3518d..d28a4b97 100644 --- a/examples/reset_reason.rs +++ b/examples/reset_reason.rs @@ -8,6 +8,8 @@ use cortex_m_rt::entry; #[macro_use] mod utilities; + +use embedded_hal::delay::DelayNs; use stm32h7xx_hal::{pac, prelude::*, rcc::ResetReason}; use log::info; @@ -48,7 +50,7 @@ fn main() -> ! { // delay 10s let mut delay = cp.SYST.delay(ccdr.clocks); - delay.delay_ms(10_000u16); + delay.delay_ms(10_000); // system reset stm32h7xx_hal::pac::SCB::sys_reset() diff --git a/examples/sdmmc.rs b/examples/sdmmc.rs index 206a6c0b..f898e70c 100644 --- a/examples/sdmmc.rs +++ b/examples/sdmmc.rs @@ -11,6 +11,7 @@ mod utilities; use cortex_m_rt::entry; +use embedded_hal::delay::DelayNs; use stm32h7xx_hal::gpio::Speed; use stm32h7xx_hal::sdmmc::{SdCard, Sdmmc}; use stm32h7xx_hal::{pac, prelude::*}; @@ -114,7 +115,7 @@ fn main() -> ! { info!("Waiting for card..."); - delay.delay_ms(1000u32); + delay.delay_ms(1000); led.toggle(); } diff --git a/examples/sdmmc_fat.rs b/examples/sdmmc_fat.rs index c451de98..89e02e75 100644 --- a/examples/sdmmc_fat.rs +++ b/examples/sdmmc_fat.rs @@ -2,6 +2,7 @@ #![no_std] use { + embedded_hal::delay::DelayNs, embedded_sdmmc::{Controller, Mode, VolumeIdx}, stm32h7xx_hal::sdmmc::{SdCard, Sdmmc}, stm32h7xx_hal::{pac, prelude::*, rcc}, diff --git a/examples/usb_phy_serial_interrupt.rs b/examples/usb_phy_serial_interrupt.rs index 90b2533a..bf14f836 100644 --- a/examples/usb_phy_serial_interrupt.rs +++ b/examples/usb_phy_serial_interrupt.rs @@ -11,6 +11,7 @@ use { core::cell::RefCell, core::mem::MaybeUninit, cortex_m::interrupt::{free as interrupt_free, Mutex}, + embedded_hal::delay::DelayNs, stm32h7xx_hal::{ interrupt, pac, prelude::*, @@ -110,10 +111,10 @@ unsafe fn main() -> ! { // clock source. Sometimes you have to enable them by yourself. // This is the case on the Arduino Portenta H7. let mut oscen = gpioh.ph1.into_push_pull_output(); - delay.delay_ms(10u32); + delay.delay_ms(10); oscen.set_high(); // Wait for osc to be stable - delay.delay_ms(100u32); + delay.delay_ms(100); // Set USB OTG pin floating let mut _usb_otg = gpioj.pj6.into_floating_input(); @@ -121,9 +122,9 @@ unsafe fn main() -> ! { // Reset USB Phy let mut usb_phy_rst = gpioj.pj4.into_push_pull_output(); usb_phy_rst.set_low(); - delay.delay_ms(10u8); + delay.delay_ms(10); usb_phy_rst.set_high(); - delay.delay_ms(10u8); + delay.delay_ms(10); // Enable USB OTG_HS interrupt cortex_m::peripheral::NVIC::unmask(pac::Interrupt::OTG_HS); diff --git a/src/delay.rs b/src/delay.rs index 31478806..5e6de07f 100644 --- a/src/delay.rs +++ b/src/delay.rs @@ -37,19 +37,12 @@ //! //! - [Blinky](https://github.com/stm32-rs/stm32h7xx-hal/blob/master/examples/blinky.rs) -use cast::u32; use cortex_m::peripheral::syst::SystClkSource; use cortex_m::peripheral::SYST; -use embedded_hal::{ - blocking::delay::{DelayMs, DelayUs}, - timer::CountDown, -}; +use embedded_hal::delay::DelayNs; use void::Void; -use crate::nb::block; use crate::rcc::CoreClocks; -use crate::time::Hertz; -use fugit::RateExtU32; pub trait DelayExt { fn delay(self, clocks: CoreClocks) -> Delay; @@ -76,7 +69,7 @@ pub struct Countdown<'a> { } impl<'a> Countdown<'a> { - /// Create a new [CountDown] measured in microseconds. + /// Create a new [Countdown] measured in microseconds. pub fn new(syst: &'a mut SYST, clocks: CoreClocks) -> Self { Self { syst, @@ -110,12 +103,11 @@ impl<'a> Countdown<'a> { } } -impl<'a> CountDown for Countdown<'a> { - type Time = fugit::MicrosDurationU32; - - fn start(&mut self, count: T) +impl<'a> Countdown<'a> { + /// Starts a new count down + pub fn start(&mut self, count: T) where - T: Into, + T: Into, { let us = count.into().ticks(); @@ -135,7 +127,8 @@ impl<'a> CountDown for Countdown<'a> { self.start_wait(); } - fn wait(&mut self) -> nb::Result<(), Void> { + /// Non-blockingly “waits” until the count down finishes + pub fn wait(&mut self) -> nb::Result<(), Void> { if self.finished { return Ok(()); } @@ -163,42 +156,12 @@ impl Delay { } } -impl DelayMs for Delay { - fn delay_ms(&mut self, ms: u32) { - self.delay_us(ms * 1_000); - } -} - -impl DelayMs for Delay { - fn delay_ms(&mut self, ms: u16) { - self.delay_ms(u32(ms)); - } -} - -impl DelayMs for Delay { - fn delay_ms(&mut self, ms: u8) { - self.delay_ms(u32(ms)); - } -} - -impl DelayUs for Delay { - fn delay_us(&mut self, us: u32) { +impl Delay { + /// Internal method to delay cycles with systick + fn systick_delay_cycles(&mut self, mut total_rvr: u64) { // The SysTick Reload Value register supports values between 1 and 0x00FFFFFF. const MAX_RVR: u32 = 0x00FF_FFFF; - // With c_ck up to 480e6, we need u64 for delays > 8.9s - - let mut total_rvr = if cfg!(not(feature = "revision_v")) { - // See errata ES0392 §2.2.3. Revision Y does not have the /8 divider - u64::from(us) * u64::from(self.clocks.c_ck().raw() / 1_000_000) - } else if cfg!(feature = "cm4") { - // CM4 derived from HCLK - u64::from(us) * u64::from(self.clocks.hclk().raw() / 8_000_000) - } else { - // Normally divide by 8 - u64::from(us) * u64::from(self.clocks.c_ck().raw() / 8_000_000) - }; - while total_rvr != 0 { let current_rvr = if total_rvr <= MAX_RVR.into() { total_rvr as u32 @@ -218,90 +181,90 @@ impl DelayUs for Delay { self.syst.disable_counter(); } } + /// Internal method that returns the clock frequency of systick + fn systick_clock(&self) -> u64 { + if cfg!(not(feature = "revision_v")) { + // See errata ES0392 §2.2.3. Revision Y does not have the /8 divider + u64::from(self.clocks.c_ck().raw()) + } else if cfg!(feature = "cm4") { + // CM4 derived from HCLK + u64::from(self.clocks.hclk().raw() / 8) + } else { + // Normally divide by 8 + u64::from(self.clocks.c_ck().raw() / 8) + } + } } -impl DelayUs for Delay { - fn delay_us(&mut self, us: u16) { - self.delay_us(u32(us)) +impl DelayNs for Delay { + fn delay_ns(&mut self, ns: u32) { + // With c_ck up to 480e6, 1 cycle is always > 2ns + + self.systick_delay_cycles(u64::from(ns + 1) / 2); + } + fn delay_us(&mut self, us: u32) { + // With c_ck up to 480e6, we need u64 for delays > 8.9s + + let total_rvr = + u64::from(us) * ((self.systick_clock() + 999_999) / 1_000_000); + self.systick_delay_cycles(total_rvr); } } -impl DelayUs for Delay { - fn delay_us(&mut self, us: u8) { - self.delay_us(u32(us)) +// embedded_hal_02 implementations +// + +impl embedded_hal_02::blocking::delay::DelayMs for Delay { + fn delay_ms(&mut self, ms: u32) { + // With c_ck up to 480e6, we need u64 for delays > 8.9s + let total_rvr = u64::from(ms) * ((self.systick_clock() + 999) / 1_000); + self.systick_delay_cycles(total_rvr); + } +} + +impl embedded_hal_02::blocking::delay::DelayMs for Delay { + fn delay_ms(&mut self, ms: u16) { + self.delay_ms(cast::u32(ms)); } } -/// CountDown Timer as a delay provider -pub struct DelayFromCountDownTimer(T); +impl embedded_hal_02::blocking::delay::DelayMs for Delay { + fn delay_ms(&mut self, ms: u8) { + self.delay_ms(cast::u32(ms)); + } +} -impl DelayFromCountDownTimer { - /// Creates delay provider from a CountDown timer - pub fn new(timer: T) -> Self { - Self(timer) +impl embedded_hal_02::blocking::delay::DelayUs for Delay { + fn delay_us(&mut self, us: u32) { + // With c_ck up to 480e6, we need u64 for delays > 8.9s + let total_rvr = + u64::from(us) * ((self.systick_clock() + 999_999) / 1_000_000); + self.systick_delay_cycles(total_rvr); } +} - /// Releases the Timer - pub fn free(self) -> T { - self.0 +impl embedded_hal_02::blocking::delay::DelayUs for Delay { + fn delay_us(&mut self, us: u16) { + self.delay_us(cast::u32(us)) } } -macro_rules! impl_delay_from_count_down_timer { - ($(($Delay:ident, $delay:ident, $num:expr)),+) => { - $( - - impl $Delay for DelayFromCountDownTimer - where - T: CountDown