From c444614096df78b3376ff0cf0828421f58e617a1 Mon Sep 17 00:00:00 2001 From: Andrew Walbran Date: Wed, 17 Jan 2024 14:22:27 +0000 Subject: [PATCH 01/10] Rename embedded-hal 0.2 in preparation for adding embedded-hal 1.0. --- nrf-hal-common/Cargo.toml | 3 ++- nrf-hal-common/src/adc.rs | 4 ++-- nrf-hal-common/src/delay.rs | 2 +- nrf-hal-common/src/gpio.rs | 4 ++-- nrf-hal-common/src/ieee802154.rs | 2 +- nrf-hal-common/src/lib.rs | 6 ++---- nrf-hal-common/src/pwm.rs | 6 +++--- nrf-hal-common/src/saadc.rs | 8 ++++---- nrf-hal-common/src/spi.rs | 2 +- nrf-hal-common/src/spim.rs | 8 ++++---- nrf-hal-common/src/timer.rs | 2 +- nrf-hal-common/src/twi.rs | 6 +++--- nrf-hal-common/src/twim.rs | 6 +++--- nrf-hal-common/src/uart.rs | 8 ++++---- nrf-hal-common/src/uarte.rs | 6 +++--- 15 files changed, 36 insertions(+), 37 deletions(-) diff --git a/nrf-hal-common/Cargo.toml b/nrf-hal-common/Cargo.toml index a6fa1c01..51d025e6 100644 --- a/nrf-hal-common/Cargo.toml +++ b/nrf-hal-common/Cargo.toml @@ -76,7 +76,8 @@ version = "0.12.2" version = "0.2.0" optional = true -[dependencies.embedded-hal] +[dependencies.embedded-hal-02] +package = "embedded-hal" features = ["unproven"] version = "0.2.4" diff --git a/nrf-hal-common/src/adc.rs b/nrf-hal-common/src/adc.rs index 62830e98..51e5def7 100644 --- a/nrf-hal-common/src/adc.rs +++ b/nrf-hal-common/src/adc.rs @@ -1,6 +1,6 @@ //! API for the Analog to Digital converter. -use embedded_hal::adc::{Channel, OneShot}; +use embedded_hal_02::adc::{Channel, OneShot}; use core::hint::unreachable_unchecked; @@ -128,7 +128,7 @@ macro_rules! channel_mappings { impl Channel for $pin { type ID = u8; - fn channel() -> >::ID { + fn channel() -> >::ID { $n } } diff --git a/nrf-hal-common/src/delay.rs b/nrf-hal-common/src/delay.rs index 8e84fcdb..6e5cc800 100644 --- a/nrf-hal-common/src/delay.rs +++ b/nrf-hal-common/src/delay.rs @@ -4,7 +4,7 @@ use cortex_m::peripheral::syst::SystClkSource; use cortex_m::peripheral::SYST; use crate::clocks::HFCLK_FREQ; -use crate::hal::blocking::delay::{DelayMs, DelayUs}; +use embedded_hal_02::blocking::delay::{DelayMs, DelayUs}; /// System timer (SysTick) as a delay provider. pub struct Delay { diff --git a/nrf-hal-common/src/gpio.rs b/nrf-hal-common/src/gpio.rs index a7b71392..091bb6ce 100644 --- a/nrf-hal-common/src/gpio.rs +++ b/nrf-hal-common/src/gpio.rs @@ -85,7 +85,7 @@ use crate::pac::P1; #[cfg(feature = "5340-net")] use crate::pac::P1_NS as P1; -use crate::hal::digital::v2::{InputPin, OutputPin, StatefulOutputPin}; +use embedded_hal_02::digital::v2::{InputPin, OutputPin, StatefulOutputPin}; use void::Void; impl Pin { @@ -482,7 +482,7 @@ macro_rules! gpio { $PX }; - use crate::hal::digital::v2::{OutputPin, StatefulOutputPin, InputPin}; + use embedded_hal_02::digital::v2::{OutputPin, StatefulOutputPin, InputPin}; use void::Void; diff --git a/nrf-hal-common/src/ieee802154.rs b/nrf-hal-common/src/ieee802154.rs index a1db7713..b832af25 100644 --- a/nrf-hal-common/src/ieee802154.rs +++ b/nrf-hal-common/src/ieee802154.rs @@ -6,7 +6,7 @@ use core::{ sync::atomic::{self, Ordering}, }; -use embedded_hal::timer::CountDown as _; +use embedded_hal_02::timer::CountDown as _; use crate::{ clocks::{Clocks, ExternalOscillator}, diff --git a/nrf-hal-common/src/lib.rs b/nrf-hal-common/src/lib.rs index 80492d91..f3b629d2 100644 --- a/nrf-hal-common/src/lib.rs +++ b/nrf-hal-common/src/lib.rs @@ -4,8 +4,6 @@ #![doc(html_root_url = "https://docs.rs/nrf-hal-common/0.16.1")] #![no_std] -use embedded_hal as hal; - #[cfg(feature = "51")] pub use nrf51_pac as pac; @@ -114,8 +112,8 @@ pub mod usbd; pub mod wdt; pub mod prelude { - pub use crate::hal::digital::v2::*; - pub use crate::hal::prelude::*; + pub use embedded_hal_02::digital::v2::*; + pub use embedded_hal_02::prelude::*; #[cfg(not(any(feature = "9160", feature = "5340-app", feature = "5340-net")))] pub use crate::ppi::{ConfigurablePpi, Ppi}; diff --git a/nrf-hal-common/src/pwm.rs b/nrf-hal-common/src/pwm.rs index 551ae0cf..add2cd3e 100644 --- a/nrf-hal-common/src/pwm.rs +++ b/nrf-hal-common/src/pwm.rs @@ -867,7 +867,7 @@ where } } -impl embedded_hal::Pwm for Pwm { +impl embedded_hal_02::Pwm for Pwm { type Channel = Channel; type Duty = u16; type Time = Hertz; @@ -944,7 +944,7 @@ impl<'a, T: Instance> PwmChannel<'a, T> { } } -impl<'a, T: Instance> embedded_hal::PwmPin for PwmChannel<'a, T> { +impl<'a, T: Instance> embedded_hal_02::PwmPin for PwmChannel<'a, T> { type Duty = u16; fn disable(&mut self) { @@ -1007,7 +1007,7 @@ impl<'a, T: Instance> PwmGroup<'a, T> { } } -impl<'a, T: Instance> embedded_hal::PwmPin for PwmGroup<'a, T> { +impl<'a, T: Instance> embedded_hal_02::PwmPin for PwmGroup<'a, T> { type Duty = u16; fn disable(&mut self) { diff --git a/nrf-hal-common/src/saadc.rs b/nrf-hal-common/src/saadc.rs index a25b092c..c6e6c11c 100644 --- a/nrf-hal-common/src/saadc.rs +++ b/nrf-hal-common/src/saadc.rs @@ -36,7 +36,7 @@ use core::{ hint::unreachable_unchecked, sync::atomic::{compiler_fence, Ordering::SeqCst}, }; -use embedded_hal::adc::{Channel, OneShot}; +use embedded_hal_02::adc::{Channel, OneShot}; pub use saadc::{ ch::config::{GAIN_A as Gain, REFSEL_A as Reference, RESP_A as Resistor, TACQ_A as Time}, @@ -230,7 +230,7 @@ macro_rules! channel_mappings { impl Channel for crate::gpio::p0::$pin { type ID = u8; - fn channel() -> >::ID { + fn channel() -> >::ID { $n } } @@ -266,7 +266,7 @@ channel_mappings! { impl Channel for InternalVdd { type ID = u8; - fn channel() -> >::ID { + fn channel() -> >::ID { 8 } } @@ -279,7 +279,7 @@ pub struct InternalVdd; impl Channel for InternalVddHdiv5 { type ID = u8; - fn channel() -> >::ID { + fn channel() -> >::ID { 13 } } diff --git a/nrf-hal-common/src/spi.rs b/nrf-hal-common/src/spi.rs index a678458d..dc2e1894 100644 --- a/nrf-hal-common/src/spi.rs +++ b/nrf-hal-common/src/spi.rs @@ -6,7 +6,7 @@ use crate::{ pac::{spi0, SPI0}, }; -pub use embedded_hal::{ +pub use embedded_hal_02::{ blocking::spi::{transfer, write, write_iter}, spi::{FullDuplex, Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}, }; diff --git a/nrf-hal-common/src/spim.rs b/nrf-hal-common/src/spim.rs index 7ba1ac03..2b63100f 100644 --- a/nrf-hal-common/src/spim.rs +++ b/nrf-hal-common/src/spim.rs @@ -14,7 +14,7 @@ use crate::pac::{SPIM1_NS as SPIM1, SPIM2_NS as SPIM2, SPIM3_NS as SPIM3}; #[cfg(not(any(feature = "9160", feature = "5340-app", feature = "5340-net")))] use crate::pac::{spim0, SPIM0}; -pub use embedded_hal::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; +pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; pub use spim0::frequency::FREQUENCY_A as Frequency; use core::iter::repeat_with; @@ -31,7 +31,7 @@ use crate::pac::SPIM3; use crate::gpio::{Floating, Input, Output, Pin, PushPull}; use crate::target_constants::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE}; use crate::{slice_in_ram, slice_in_ram_or, DmaSlice}; -use embedded_hal::digital::v2::OutputPin; +use embedded_hal_02::digital::v2::OutputPin; /// Interface to a SPIM instance. /// @@ -41,7 +41,7 @@ use embedded_hal::digital::v2::OutputPin; /// are disabled before using `Spim`. See product specification, section 15.2. pub struct Spim(T); -impl embedded_hal::blocking::spi::Transfer for Spim +impl embedded_hal_02::blocking::spi::Transfer for Spim where T: Instance, { @@ -59,7 +59,7 @@ where } } -impl embedded_hal::blocking::spi::Write for Spim +impl embedded_hal_02::blocking::spi::Write for Spim where T: Instance, { diff --git a/nrf-hal-common/src/timer.rs b/nrf-hal-common/src/timer.rs index 0c9169a0..a1240885 100644 --- a/nrf-hal-common/src/timer.rs +++ b/nrf-hal-common/src/timer.rs @@ -20,7 +20,7 @@ use crate::pac::{ Interrupt, TIMER0, TIMER1, TIMER2, }; use cast::u32; -use embedded_hal::{ +use embedded_hal_02::{ blocking::delay::{DelayMs, DelayUs}, prelude::*, timer, diff --git a/nrf-hal-common/src/twi.rs b/nrf-hal-common/src/twi.rs index 0237fcb8..a956b3d3 100644 --- a/nrf-hal-common/src/twi.rs +++ b/nrf-hal-common/src/twi.rs @@ -250,7 +250,7 @@ where } } -impl embedded_hal::blocking::i2c::Write for Twi +impl embedded_hal_02::blocking::i2c::Write for Twi where T: Instance, { @@ -261,7 +261,7 @@ where } } -impl embedded_hal::blocking::i2c::Read for Twi +impl embedded_hal_02::blocking::i2c::Read for Twi where T: Instance, { @@ -272,7 +272,7 @@ where } } -impl embedded_hal::blocking::i2c::WriteRead for Twi +impl embedded_hal_02::blocking::i2c::WriteRead for Twi where T: Instance, { diff --git a/nrf-hal-common/src/twim.rs b/nrf-hal-common/src/twim.rs index 086a984c..6bb44644 100644 --- a/nrf-hal-common/src/twim.rs +++ b/nrf-hal-common/src/twim.rs @@ -394,7 +394,7 @@ where } } -impl embedded_hal::blocking::i2c::Write for Twim +impl embedded_hal_02::blocking::i2c::Write for Twim where T: Instance, { @@ -414,7 +414,7 @@ where } } -impl embedded_hal::blocking::i2c::Read for Twim +impl embedded_hal_02::blocking::i2c::Read for Twim where T: Instance, { @@ -425,7 +425,7 @@ where } } -impl embedded_hal::blocking::i2c::WriteRead for Twim +impl embedded_hal_02::blocking::i2c::WriteRead for Twim where T: Instance, { diff --git a/nrf-hal-common/src/uart.rs b/nrf-hal-common/src/uart.rs index 88711525..fb18da55 100644 --- a/nrf-hal-common/src/uart.rs +++ b/nrf-hal-common/src/uart.rs @@ -99,7 +99,7 @@ where } } -impl embedded_hal::serial::Read for Uart +impl embedded_hal_02::serial::Read for Uart where T: Instance, { @@ -121,7 +121,7 @@ where } } -impl embedded_hal::serial::Write for Uart +impl embedded_hal_02::serial::Write for Uart where T: Instance, { @@ -150,10 +150,10 @@ where impl Write for Uart where - Uart: embedded_hal::serial::Write, + Uart: embedded_hal_02::serial::Write, { fn write_str(&mut self, s: &str) -> fmt::Result { - use embedded_hal::serial::Write; + use embedded_hal_02::serial::Write; let _ = s.as_bytes().iter().map(|c| block!(self.write(*c))).last(); Ok(()) } diff --git a/nrf-hal-common/src/uarte.rs b/nrf-hal-common/src/uarte.rs index 7975185f..65c15394 100644 --- a/nrf-hal-common/src/uarte.rs +++ b/nrf-hal-common/src/uarte.rs @@ -8,9 +8,9 @@ use core::fmt; use core::ops::Deref; use core::sync::atomic::{compiler_fence, Ordering::SeqCst}; -use embedded_hal::blocking::serial as bserial; -use embedded_hal::digital::v2::OutputPin; -use embedded_hal::serial; +use embedded_hal_02::blocking::serial as bserial; +use embedded_hal_02::digital::v2::OutputPin; +use embedded_hal_02::serial; #[cfg(any(feature = "52833", feature = "52840"))] use crate::pac::UARTE1; From 9959e56e547dd2d9533c0d7ed24a001287c06b3a Mon Sep 17 00:00:00 2001 From: Andrew Walbran Date: Wed, 17 Jan 2024 14:55:01 +0000 Subject: [PATCH 02/10] Implement embedded-hal 1.0 DelayNs for Delay. --- nrf-hal-common/Cargo.toml | 3 +++ nrf-hal-common/src/delay.rs | 40 +++++++++++++++++++++---------------- 2 files changed, 26 insertions(+), 17 deletions(-) diff --git a/nrf-hal-common/Cargo.toml b/nrf-hal-common/Cargo.toml index 51d025e6..e41ee2b6 100644 --- a/nrf-hal-common/Cargo.toml +++ b/nrf-hal-common/Cargo.toml @@ -81,6 +81,9 @@ package = "embedded-hal" features = ["unproven"] version = "0.2.4" +[dependencies.embedded-hal] +version = "1.0.0" + [features] doc = [] 51 = ["nrf51-pac"] diff --git a/nrf-hal-common/src/delay.rs b/nrf-hal-common/src/delay.rs index 6e5cc800..19090234 100644 --- a/nrf-hal-common/src/delay.rs +++ b/nrf-hal-common/src/delay.rs @@ -1,9 +1,9 @@ //! Delays. -use cast::u32; use cortex_m::peripheral::syst::SystClkSource; use cortex_m::peripheral::SYST; use crate::clocks::HFCLK_FREQ; +use embedded_hal::delay::DelayNs; use embedded_hal_02::blocking::delay::{DelayMs, DelayUs}; /// System timer (SysTick) as a delay provider. @@ -27,28 +27,46 @@ impl Delay { impl DelayMs for Delay { fn delay_ms(&mut self, ms: u32) { - self.delay_us(ms * 1_000); + DelayNs::delay_ms(self, ms); } } impl DelayMs for Delay { fn delay_ms(&mut self, ms: u16) { - self.delay_ms(u32(ms)); + DelayNs::delay_ms(self, ms.into()); } } impl DelayMs for Delay { fn delay_ms(&mut self, ms: u8) { - self.delay_ms(u32(ms)); + DelayNs::delay_ms(self, ms.into()); } } impl DelayUs for Delay { fn delay_us(&mut self, us: u32) { + DelayNs::delay_us(self, us); + } +} + +impl DelayUs for Delay { + fn delay_us(&mut self, us: u16) { + DelayNs::delay_us(self, us.into()); + } +} + +impl DelayUs for Delay { + fn delay_us(&mut self, us: u8) { + DelayNs::delay_us(self, us.into()); + } +} + +impl DelayNs for Delay { + fn delay_ns(&mut self, ns: u32) { // The SysTick Reload Value register supports values between 1 and 0x00FFFFFF. const MAX_RVR: u32 = 0x00FF_FFFF; - let mut total_rvr = us * (HFCLK_FREQ / 1_000_000); + let mut total_rvr = ns * (HFCLK_FREQ / 1_000_000_000); while total_rvr != 0 { let current_rvr = if total_rvr <= MAX_RVR { @@ -70,15 +88,3 @@ impl DelayUs for Delay { } } } - -impl DelayUs for Delay { - fn delay_us(&mut self, us: u16) { - self.delay_us(u32(us)) - } -} - -impl DelayUs for Delay { - fn delay_us(&mut self, us: u8) { - self.delay_us(u32(us)) - } -} From 7312c9e407fd0e0c9f7feb298a42556242b0dc8a Mon Sep 17 00:00:00 2001 From: Andrew Walbran Date: Wed, 17 Jan 2024 15:08:24 +0000 Subject: [PATCH 03/10] Implement embedded-hal 1.0 traits for GPIO types. --- nrf-hal-common/src/gpio.rs | 127 ++++++++++++++++++++++++++++++++++--- 1 file changed, 117 insertions(+), 10 deletions(-) diff --git a/nrf-hal-common/src/gpio.rs b/nrf-hal-common/src/gpio.rs index 091bb6ce..305c7bd8 100644 --- a/nrf-hal-common/src/gpio.rs +++ b/nrf-hal-common/src/gpio.rs @@ -1,4 +1,4 @@ -use core::marker::PhantomData; +use core::{convert::Infallible, marker::PhantomData}; /// Disconnected pin in input mode (type state, reset value). pub struct Disconnected; @@ -85,7 +85,7 @@ use crate::pac::P1; #[cfg(feature = "5340-net")] use crate::pac::P1_NS as P1; -use embedded_hal_02::digital::v2::{InputPin, OutputPin, StatefulOutputPin}; +use embedded_hal::digital::{ErrorType, InputPin, OutputPin, StatefulOutputPin}; use void::Void; impl Pin { @@ -348,7 +348,63 @@ impl Pin { } } +impl ErrorType for Pin { + type Error = Infallible; +} + impl InputPin for Pin> { + fn is_high(&mut self) -> Result { + self.is_low().map(|v| !v) + } + + fn is_low(&mut self) -> Result { + Ok(self.block().in_.read().bits() & (1 << self.pin()) == 0) + } +} + +impl InputPin for Pin> { + fn is_high(&mut self) -> Result { + self.is_low().map(|v| !v) + } + + fn is_low(&mut self) -> Result { + Ok(self.block().in_.read().bits() & (1 << self.pin()) == 0) + } +} + +impl OutputPin for Pin> { + fn set_high(&mut self) -> Result<(), Self::Error> { + // NOTE(unsafe) atomic write to a stateless register - TODO(AJM) verify? + // TODO - I wish I could do something like `.pins$i()`... + unsafe { + self.block().outset.write(|w| w.bits(1u32 << self.pin())); + } + Ok(()) + } + + fn set_low(&mut self) -> Result<(), Self::Error> { + // NOTE(unsafe) atomic write to a stateless register - TODO(AJM) verify? + // TODO - I wish I could do something like `.pins$i()`... + unsafe { + self.block().outclr.write(|w| w.bits(1u32 << self.pin())); + } + Ok(()) + } +} + +impl StatefulOutputPin for Pin> { + fn is_set_high(&mut self) -> Result { + self.is_set_low().map(|v| !v) + } + + fn is_set_low(&mut self) -> Result { + // NOTE(unsafe) atomic read with no side effects - TODO(AJM) verify? + // TODO - I wish I could do something like `.pins$i()`... + Ok(self.block().out.read().bits() & (1 << self.pin()) == 0) + } +} + +impl embedded_hal_02::digital::v2::InputPin for Pin> { type Error = Void; fn is_high(&self) -> Result { @@ -360,7 +416,7 @@ impl InputPin for Pin> { } } -impl InputPin for Pin> { +impl embedded_hal_02::digital::v2::InputPin for Pin> { type Error = Void; fn is_high(&self) -> Result { @@ -372,7 +428,7 @@ impl InputPin for Pin> { } } -impl OutputPin for Pin> { +impl embedded_hal_02::digital::v2::OutputPin for Pin> { type Error = Void; /// Set the output as high. @@ -396,7 +452,7 @@ impl OutputPin for Pin> { } } -impl StatefulOutputPin for Pin> { +impl embedded_hal_02::digital::v2::StatefulOutputPin for Pin> { /// Is the output pin set as high? fn is_set_high(&self) -> Result { self.is_set_low().map(|v| !v) @@ -482,10 +538,10 @@ macro_rules! gpio { $PX }; - use embedded_hal_02::digital::v2::{OutputPin, StatefulOutputPin, InputPin}; + use core::convert::Infallible; + use embedded_hal::digital::{ErrorType, InputPin, OutputPin, StatefulOutputPin}; use void::Void; - // =============================================================== // This chunk allows you to obtain an nrf-hal gpio from the // upstream nrf52 gpio definitions by defining a trait @@ -695,7 +751,58 @@ macro_rules! gpio { } } + impl ErrorType for $PXi { + type Error = Infallible; + } + impl InputPin for $PXi> { + fn is_high(&mut self) -> Result { + self.is_low().map(|v| !v) + } + + fn is_low(&mut self) -> Result { + Ok(unsafe { ((*$PX::ptr()).in_.read().bits() & (1 << $i)) == 0 }) + } + } + + impl InputPin for $PXi> { + fn is_high(&mut self) -> Result { + self.is_low().map(|v| !v) + } + + fn is_low(&mut self) -> Result { + Ok(unsafe { ((*$PX::ptr()).in_.read().bits() & (1 << $i)) == 0 }) + } + } + impl OutputPin for $PXi> { + fn set_high(&mut self) -> Result<(), Self::Error> { + // NOTE(unsafe) atomic write to a stateless register - TODO(AJM) verify? + // TODO - I wish I could do something like `.pins$i()`... + unsafe { (*$PX::ptr()).outset.write(|w| w.bits(1u32 << $i)); } + Ok(()) + } + + fn set_low(&mut self) -> Result<(), Self::Error> { + // NOTE(unsafe) atomic write to a stateless register - TODO(AJM) verify? + // TODO - I wish I could do something like `.pins$i()`... + unsafe { (*$PX::ptr()).outclr.write(|w| w.bits(1u32 << $i)); } + Ok(()) + } + } + + impl StatefulOutputPin for $PXi> { + fn is_set_high(&mut self) -> Result { + self.is_set_low().map(|v| !v) + } + + fn is_set_low(&mut self) -> Result { + // NOTE(unsafe) atomic read with no side effects - TODO(AJM) verify? + // TODO - I wish I could do something like `.pins$i()`... + Ok(unsafe { ((*$PX::ptr()).out.read().bits() & (1 << $i)) == 0 }) + } + } + + impl embedded_hal_02::digital::v2::InputPin for $PXi> { type Error = Void; fn is_high(&self) -> Result { @@ -707,7 +814,7 @@ macro_rules! gpio { } } - impl InputPin for $PXi> { + impl embedded_hal_02::digital::v2::InputPin for $PXi> { type Error = Void; fn is_high(&self) -> Result { @@ -725,7 +832,7 @@ macro_rules! gpio { } } - impl OutputPin for $PXi> { + impl embedded_hal_02::digital::v2::OutputPin for $PXi> { type Error = Void; /// Set the output as high @@ -745,7 +852,7 @@ macro_rules! gpio { } } - impl StatefulOutputPin for $PXi> { + impl embedded_hal_02::digital::v2::StatefulOutputPin for $PXi> { /// Is the output pin set as high? fn is_set_high(&self) -> Result { self.is_set_low().map(|v| !v) From 50d0c839dd6f8f7ff79048f6f4b1fc75a13c5df6 Mon Sep 17 00:00:00 2001 From: Andrew Walbran Date: Wed, 17 Jan 2024 15:14:39 +0000 Subject: [PATCH 04/10] Implement embedded-hal 1.0 traits for PWM types. --- nrf-hal-common/src/pwm.rs | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/nrf-hal-common/src/pwm.rs b/nrf-hal-common/src/pwm.rs index add2cd3e..c8356f8f 100644 --- a/nrf-hal-common/src/pwm.rs +++ b/nrf-hal-common/src/pwm.rs @@ -15,10 +15,12 @@ use crate::{ }; use core::{ cell::Cell, + convert::Infallible, ops::Deref, sync::atomic::{compiler_fence, Ordering}, }; use embedded_dma::*; +use embedded_hal::pwm::{ErrorType, SetDutyCycle}; const MAX_SEQ_LEN: usize = 0x7FFF; @@ -968,6 +970,21 @@ impl<'a, T: Instance> embedded_hal_02::PwmPin for PwmChannel<'a, T> { } } +impl<'a, T: Instance> ErrorType for PwmChannel<'a, T> { + type Error = Infallible; +} + +impl<'a, T: Instance> SetDutyCycle for PwmChannel<'a, T> { + fn max_duty_cycle(&self) -> u16 { + self.max_duty() + } + + fn set_duty_cycle(&mut self, duty: u16) -> Result<(), Self::Error> { + self.set_duty_on(duty); + Ok(()) + } +} + /// PWM group #[derive(Debug)] pub struct PwmGroup<'a, T: Instance> { @@ -1031,6 +1048,21 @@ impl<'a, T: Instance> embedded_hal_02::PwmPin for PwmGroup<'a, T> { } } +impl<'a, T: Instance> ErrorType for PwmGroup<'a, T> { + type Error = Infallible; +} + +impl<'a, T: Instance> SetDutyCycle for PwmGroup<'a, T> { + fn max_duty_cycle(&self) -> u16 { + self.max_duty() + } + + fn set_duty_cycle(&mut self, duty: u16) -> Result<(), Self::Error> { + self.set_duty_on(duty); + Ok(()) + } +} + #[derive(Debug, Eq, PartialEq, Clone, Copy)] pub enum Channel { C0, From 13396cb14a2785ea6490ae6e83146c6d22479f35 Mon Sep 17 00:00:00 2001 From: Andrew Walbran Date: Wed, 17 Jan 2024 15:47:34 +0000 Subject: [PATCH 05/10] Implement embedded-hal 1.0 SpiBus for Spi. --- nrf-hal-common/src/spi.rs | 63 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/nrf-hal-common/src/spi.rs b/nrf-hal-common/src/spi.rs index dc2e1894..bf241d03 100644 --- a/nrf-hal-common/src/spi.rs +++ b/nrf-hal-common/src/spi.rs @@ -6,12 +6,17 @@ use crate::{ pac::{spi0, SPI0}, }; +use core::{cmp::max, convert::Infallible, hint::spin_loop}; +use embedded_hal::spi::{ErrorType, SpiBus}; pub use embedded_hal_02::{ blocking::spi::{transfer, write, write_iter}, spi::{FullDuplex, Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}, }; pub use spi0::frequency::FREQUENCY_A as Frequency; +/// Value written out if the caller requests a read without data to write. +const DEFAULT_WRITE: u8 = 0x00; + /// Interface to a SPI instance. pub struct Spi(T); @@ -65,6 +70,48 @@ where } } +impl ErrorType for Spi { + type Error = Infallible; +} + +impl SpiBus for Spi { + fn read(&mut self, words: &mut [u8]) -> Result<(), Self::Error> { + for word in words { + *word = self.transfer_word(DEFAULT_WRITE); + } + Ok(()) + } + + fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> { + for word in words { + self.transfer_word(*word); + } + Ok(()) + } + + fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Self::Error> { + for i in 0..max(read.len(), write.len()) { + let read_byte = self.transfer_word(write.get(i).copied().unwrap_or(DEFAULT_WRITE)); + if i < read.len() { + read[i] = read_byte + } + } + Ok(()) + } + + fn transfer_in_place(&mut self, words: &mut [u8]) -> Result<(), Self::Error> { + for word in words { + *word = self.transfer_word(*word); + } + Ok(()) + } + + fn flush(&mut self) -> Result<(), Self::Error> { + // This implementation doesn't buffer operations, so there is nothing to flush. + Ok(()) + } +} + impl Spi where T: Instance, @@ -133,6 +180,22 @@ where } } + /// Writes and reads a single 8-bit word. + fn transfer_word(&mut self, write: u8) -> u8 { + self.0.txd.write(|w| unsafe { w.bits(u32::from(write)) }); + + // Wait for a word to be available to read. + while self.0.events_ready.read().bits() == 0 { + spin_loop(); + } + // Read one 8-bit value. + let read = self.0.rxd.read().bits() as u8; + // Reset ready for receive event. + self.0.events_ready.reset(); + + read + } + /// Return the raw interface to the underlying SPI peripheral. pub fn free(self) -> T { self.0 From f16e6bf77a4fd744a97354673731bd69f8e55183 Mon Sep 17 00:00:00 2001 From: Andrew Walbran Date: Wed, 17 Jan 2024 16:04:22 +0000 Subject: [PATCH 06/10] Implement embedded-hal 1.0 DelayNs for Timer. --- nrf-hal-common/src/timer.rs | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/nrf-hal-common/src/timer.rs b/nrf-hal-common/src/timer.rs index a1240885..3b2caa7b 100644 --- a/nrf-hal-common/src/timer.rs +++ b/nrf-hal-common/src/timer.rs @@ -20,6 +20,7 @@ use crate::pac::{ Interrupt, TIMER0, TIMER1, TIMER2, }; use cast::u32; +use embedded_hal::delay::DelayNs; use embedded_hal_02::{ blocking::delay::{DelayMs, DelayUs}, prelude::*, @@ -299,7 +300,7 @@ where T: Instance, { fn delay_ms(&mut self, ms: u32) { - self.delay_us(ms * 1_000); + DelayUs::delay_us(self, ms * 1_000); } } @@ -308,7 +309,7 @@ where T: Instance, { fn delay_ms(&mut self, ms: u16) { - self.delay_ms(u32(ms)); + DelayMs::delay_ms(self, u32(ms)); } } @@ -317,7 +318,7 @@ where T: Instance, { fn delay_ms(&mut self, ms: u8) { - self.delay_ms(u32(ms)); + DelayMs::delay_ms(self, u32(ms)); } } @@ -335,7 +336,7 @@ where T: Instance, { fn delay_us(&mut self, us: u16) { - self.delay_us(u32(us)) + DelayUs::delay_us(self, u32(us)) } } @@ -344,7 +345,13 @@ where T: Instance, { fn delay_us(&mut self, us: u8) { - self.delay_us(u32(us)) + DelayUs::delay_us(self, u32(us)) + } +} + +impl DelayNs for Timer { + fn delay_ns(&mut self, ns: u32) { + self.delay(ns / 1_000); } } From 5aaa517e63c8951ea1245be3736d19900fe6c2a3 Mon Sep 17 00:00:00 2001 From: Andrew Walbran Date: Wed, 17 Jan 2024 17:47:28 +0000 Subject: [PATCH 07/10] Implement embedded-hal 1.0 SpiBus for Spim. Also removed unused error variants. --- nrf-hal-common/src/spim.rs | 154 +++++++++++++++++++++++++++---------- 1 file changed, 115 insertions(+), 39 deletions(-) diff --git a/nrf-hal-common/src/spim.rs b/nrf-hal-common/src/spim.rs index 2b63100f..ddc9a505 100644 --- a/nrf-hal-common/src/spim.rs +++ b/nrf-hal-common/src/spim.rs @@ -4,6 +4,8 @@ use core::ops::Deref; use core::sync::atomic::{compiler_fence, Ordering::SeqCst}; +use embedded_hal::digital::OutputPin; +use embedded_hal::spi::{self, ErrorKind, ErrorType, SpiBus}; #[cfg(any(feature = "9160", feature = "5340-app", feature = "5340-net"))] use crate::pac::{spim0_ns as spim0, SPIM0_NS as SPIM0}; @@ -31,7 +33,6 @@ use crate::pac::SPIM3; use crate::gpio::{Floating, Input, Output, Pin, PushPull}; use crate::target_constants::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE}; use crate::{slice_in_ram, slice_in_ram_or, DmaSlice}; -use embedded_hal_02::digital::v2::OutputPin; /// Interface to a SPIM instance. /// @@ -41,6 +42,61 @@ use embedded_hal_02::digital::v2::OutputPin; /// are disabled before using `Spim`. See product specification, section 15.2. pub struct Spim(T); +impl ErrorType for Spim { + type Error = Error; +} + +impl SpiBus for Spim { + fn read(&mut self, words: &mut [u8]) -> Result<(), Self::Error> { + // A mutable slice can only be built from data in RAM. + assert!(slice_in_ram(words)); + + for chunk in words.chunks(EASY_DMA_SIZE) { + self.do_spi_dma_transfer(DmaSlice::null(), DmaSlice::from_slice(chunk))?; + } + Ok(()) + } + + fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> { + if slice_in_ram(words) { + for chunk in words.chunks(EASY_DMA_SIZE) { + self.do_spi_dma_transfer(DmaSlice::from_slice(chunk), DmaSlice::null())?; + } + } else { + let mut buf = [0u8; FORCE_COPY_BUFFER_SIZE]; + for chunk in words.chunks(FORCE_COPY_BUFFER_SIZE) { + buf[..chunk.len()].copy_from_slice(chunk); + self.do_spi_dma_transfer( + DmaSlice::from_slice(&buf[..chunk.len()]), + DmaSlice::null(), + )?; + } + } + + Ok(()) + } + + fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Self::Error> { + self.transfer_split_uneven_internal(write, read) + } + + fn transfer_in_place(&mut self, words: &mut [u8]) -> Result<(), Self::Error> { + // A mutable slice can only be built from data in RAM. + assert!(slice_in_ram(words)); + + words.chunks(EASY_DMA_SIZE).try_for_each(|chunk| { + self.do_spi_dma_transfer(DmaSlice::from_slice(chunk), DmaSlice::from_slice(chunk)) + })?; + + Ok(()) + } + + fn flush(&mut self) -> Result<(), Self::Error> { + // This implementation doesn't buffer operations, so there is nothing to flush. + Ok(()) + } +} + impl embedded_hal_02::blocking::spi::Transfer for Spim where T: Instance, @@ -85,6 +141,7 @@ where words.chunks(chunk_sz).try_for_each(|c| step(self, c)) } } + impl Spim where T: Instance, @@ -304,50 +361,65 @@ where tx_buffer: &[u8], rx_buffer: &mut [u8], ) -> Result<(), Error> { - // NOTE: RAM slice check for `rx_buffer` is not necessary, as a mutable - // slice can only be built from data located in RAM. slice_in_ram_or(tx_buffer, Error::DMABufferNotInDataMemory)?; - // For the tx and rx, we want to return Some(chunk) - // as long as there is data to send. We then chain a repeat to - // the end so once all chunks have been exhausted, we will keep - // getting Nones out of the iterators. - let txi = tx_buffer - .chunks(EASY_DMA_SIZE) - .map(Some) - .chain(repeat_with(|| None)); - - let rxi = rx_buffer - .chunks_mut(EASY_DMA_SIZE) - .map(Some) - .chain(repeat_with(|| None)); - chip_select.set_low().unwrap(); - - // We then chain the iterators together, and once BOTH are feeding - // back Nones, then we are done sending and receiving. - // // Don't return early, as we must reset the CS pin. - let res = txi - .zip(rxi) - .take_while(|(t, r)| t.is_some() || r.is_some()) - // We also turn the slices into either a DmaSlice (if there was data), or a null - // DmaSlice (if there is no data). - .map(|(t, r)| { - ( - t.map(|t| DmaSlice::from_slice(t)) - .unwrap_or_else(DmaSlice::null), - r.map(|r| DmaSlice::from_slice(r)) - .unwrap_or_else(DmaSlice::null), - ) - }) - .try_for_each(|(t, r)| self.do_spi_dma_transfer(t, r)); - + let res = self.transfer_split_uneven_internal(tx_buffer, rx_buffer); chip_select.set_high().unwrap(); - res } + pub fn transfer_split_uneven_internal( + &mut self, + tx_buffer: &[u8], + rx_buffer: &mut [u8], + ) -> Result<(), Error> { + // NOTE: RAM slice check for `rx_buffer` is not necessary, as a mutable + // slice can only be built from data located in RAM. + if slice_in_ram(tx_buffer) { + // For the tx and rx, we want to return a DmaSlice with a chunk as long + // as there is data to send. We then chain a repeat to the end so once + // all chunks have been exhausted, we will keep DmaSlice::null() out of + // the iterators. + let txi = tx_buffer + .chunks(EASY_DMA_SIZE) + .map(|chunk| DmaSlice::from_slice(chunk)) + .chain(repeat_with(DmaSlice::null)); + let rxi = rx_buffer + .chunks_mut(EASY_DMA_SIZE) + .map(|chunk| DmaSlice::from_slice(chunk)) + .chain(repeat_with(DmaSlice::null)); + + // We then chain the iterators together, and once BOTH are giving null + // DmaSlices, then we are done sending and receiving. + for (t, r) in txi.zip(rxi).take_while(|(t, r)| t.ptr != 0 || r.ptr != 0) { + self.do_spi_dma_transfer(t, r)?; + } + } else { + let mut buf = [0u8; FORCE_COPY_BUFFER_SIZE]; + let txi = tx_buffer + .chunks(FORCE_COPY_BUFFER_SIZE) + .map(Some) + .chain(repeat_with(|| None)); + let rxi = rx_buffer + .chunks_mut(FORCE_COPY_BUFFER_SIZE) + .map(|chunk| DmaSlice::from_slice(chunk)) + .chain(repeat_with(DmaSlice::null)); + for (tx_chunk, r) in txi.zip(rxi).take_while(|(t, r)| t.is_some() || r.ptr != 0) { + let t = if let Some(tx_chunk) = tx_chunk { + buf[..tx_chunk.len()].copy_from_slice(tx_chunk); + DmaSlice::from_slice(&buf[..tx_chunk.len()]) + } else { + DmaSlice::null() + }; + self.do_spi_dma_transfer(t, r)?; + } + } + + Ok(()) + } + /// Write to an SPI slave. /// /// This method uses the provided chip select pin to initiate the @@ -411,14 +483,18 @@ pub struct Pins { #[derive(Debug)] pub enum Error { - TxBufferTooLong, - RxBufferTooLong, /// EasyDMA can only read from data memory, read only buffers in flash will fail. DMABufferNotInDataMemory, Transmit, Receive, } +impl spi::Error for Error { + fn kind(&self) -> ErrorKind { + ErrorKind::Other + } +} + /// Implemented by all SPIM instances. pub trait Instance: Deref + sealed::Sealed {} From 574005a8850b60019c8a0d065273bbbd48d1a659 Mon Sep 17 00:00:00 2001 From: Andrew Walbran Date: Wed, 17 Jan 2024 18:15:07 +0000 Subject: [PATCH 08/10] Implement embedded-io traits for Uart. --- nrf-hal-common/Cargo.toml | 3 ++ nrf-hal-common/src/uart.rs | 68 +++++++++++++++++++++++++++++++++++++- 2 files changed, 70 insertions(+), 1 deletion(-) diff --git a/nrf-hal-common/Cargo.toml b/nrf-hal-common/Cargo.toml index e41ee2b6..1cf5b358 100644 --- a/nrf-hal-common/Cargo.toml +++ b/nrf-hal-common/Cargo.toml @@ -84,6 +84,9 @@ version = "0.2.4" [dependencies.embedded-hal] version = "1.0.0" +[dependencies.embedded-io] +version = "0.6.1" + [features] doc = [] 51 = ["nrf51-pac"] diff --git a/nrf-hal-common/src/uart.rs b/nrf-hal-common/src/uart.rs index fb18da55..0b4e514e 100644 --- a/nrf-hal-common/src/uart.rs +++ b/nrf-hal-common/src/uart.rs @@ -1,8 +1,10 @@ //! HAL interface to the UART peripheral. +use core::convert::Infallible; use core::fmt::{self, Write}; +use core::hint::spin_loop; use core::ops::Deref; - +use embedded_io::{ErrorType, Read, ReadReady, WriteReady}; use nb::block; use void::Void; @@ -99,6 +101,70 @@ where } } +impl ErrorType for Uart { + type Error = Infallible; +} + +impl ReadReady for Uart { + fn read_ready(&mut self) -> Result { + Ok(self.0.events_rxdrdy.read().bits() != 0) + } +} + +impl Read for Uart { + fn read(&mut self, buf: &mut [u8]) -> Result { + if buf.is_empty() { + return Ok(0); + } + + while !self.read_ready()? { + spin_loop(); + } + + // Reset ready for receive event. + self.0.events_rxdrdy.reset(); + + // Read one 8bit value. + buf[0] = self.0.rxd.read().bits() as u8; + + Ok(1) + } +} + +impl WriteReady for Uart { + fn write_ready(&mut self) -> Result { + Ok(self.0.events_txdrdy.read().bits() == 1) + } +} + +impl embedded_io::Write for Uart { + fn write(&mut self, buf: &[u8]) -> Result { + if buf.is_empty() { + return Ok(0); + } + + // Wait until we are ready to send out a byte. + while !self.write_ready()? { + spin_loop(); + } + + // Reset ready for transmit event. + self.0.events_txdrdy.reset(); + + // Send a single byte. + self.0.txd.write(|w| unsafe { w.bits(buf[0].into()) }); + + Ok(1) + } + + fn flush(&mut self) -> Result<(), Self::Error> { + while !self.write_ready()? { + spin_loop(); + } + Ok(()) + } +} + impl embedded_hal_02::serial::Read for Uart where T: Instance, From 4f15555de832280ea135928fab99732e84214788 Mon Sep 17 00:00:00 2001 From: Andrew Walbran Date: Wed, 17 Jan 2024 19:18:42 +0000 Subject: [PATCH 09/10] Implement embedded-io traits for uarte types. --- nrf-hal-common/src/uarte.rs | 128 ++++++++++++++++++++++++++++++++++-- 1 file changed, 122 insertions(+), 6 deletions(-) diff --git a/nrf-hal-common/src/uarte.rs b/nrf-hal-common/src/uarte.rs index 65c15394..a029cad1 100644 --- a/nrf-hal-common/src/uarte.rs +++ b/nrf-hal-common/src/uarte.rs @@ -4,23 +4,23 @@ //! //! - nrf52832: Section 35 //! - nrf52840: Section 6.34 + +use core::cmp::min; use core::fmt; +use core::hint::spin_loop; use core::ops::Deref; use core::sync::atomic::{compiler_fence, Ordering::SeqCst}; - use embedded_hal_02::blocking::serial as bserial; use embedded_hal_02::digital::v2::OutputPin; use embedded_hal_02::serial; +use embedded_io::{ErrorKind, ErrorType, ReadReady, WriteReady}; #[cfg(any(feature = "52833", feature = "52840"))] use crate::pac::UARTE1; #[cfg(feature = "9160")] use crate::pac::{ - uarte0_ns as uarte0, - UARTE0_NS as UARTE0, - UARTE1_NS as UARTE1, - UARTE2_NS as UARTE2, + uarte0_ns as uarte0, UARTE0_NS as UARTE0, UARTE1_NS as UARTE1, UARTE2_NS as UARTE2, UARTE3_NS as UARTE3, }; @@ -421,6 +421,9 @@ fn start_read(uarte: &uarte0::RegisterBlock, rx_buffer: &mut [u8]) -> Result<(), uarte.tasks_startrx.write(|w| // `1` is a valid value to write to task registers. unsafe { w.bits(1) }); + while uarte.events_rxstarted.read().bits() == 0 { + spin_loop(); + } Ok(()) } @@ -492,6 +495,20 @@ pub enum Error { BufferNotInRAM, } +impl embedded_io::Error for Error { + fn kind(&self) -> ErrorKind { + match self { + Self::TxBufferTooSmall + | Self::RxBufferTooSmall + | Self::TxBufferTooLong + | Self::RxBufferTooLong + | Self::BufferNotInRAM => ErrorKind::InvalidInput, + Self::Transmit | Self::Receive => ErrorKind::Interrupted, + Self::Timeout(_) => ErrorKind::TimedOut, + } + } +} + pub trait Instance: Deref + sealed::Sealed { fn ptr() -> *const uarte0::RegisterBlock; } @@ -662,6 +679,52 @@ where } } +impl ErrorType for UarteTx { + type Error = Error; +} + +impl WriteReady for UarteTx { + fn write_ready(&mut self) -> Result { + let uarte = unsafe { &*T::ptr() }; + + let dma_transfer_in_progress = + uarte.events_txstarted.read().bits() == 1 && uarte.events_endtx.read().bits() == 0; + + Ok(!dma_transfer_in_progress && self.written < self.tx_buf.len()) + } +} + +impl embedded_io::Write for UarteTx { + fn write(&mut self, buf: &[u8]) -> Result { + if buf.is_empty() { + return Ok(0); + } + + // If the internal buffer is full or a DMA transfer is in progress, flush and block until it + // is finished. + if !self.write_ready()? { + nb::block!(serial::Write::flush(self))?; + } + + // Copy as many bytes as possible to the internal TX buffer. + let length_to_copy = min(buf.len(), self.tx_buf.len() - self.written); + self.tx_buf[self.written..].copy_from_slice(&buf[..length_to_copy]); + self.written += length_to_copy; + + // If the internal buffer is now full, flush but don't block. + match serial::Write::flush(self) { + Err(nb::Error::Other(e)) => return Err(e), + _ => {} + } + + Ok(length_to_copy) + } + + fn flush(&mut self) -> Result<(), Self::Error> { + nb::block!(serial::Write::flush(self)) + } +} + impl serial::Write for UarteTx where T: Instance, @@ -748,6 +811,59 @@ where } } +impl ErrorType for UarteRx { + type Error = Error; +} + +impl ReadReady for UarteRx { + fn read_ready(&mut self) -> Result { + let uarte = unsafe { &*T::ptr() }; + + compiler_fence(SeqCst); + + if uarte.events_rxstarted.read().bits() == 0 { + start_read(uarte, self.rx_buf)?; + Ok(false) + } else { + Ok(uarte.events_endrx.read().bits() != 0) + } + } +} + +impl embedded_io::Read for UarteRx { + fn read(&mut self, buf: &mut [u8]) -> Result { + if buf.is_empty() { + return Ok(0); + } + + let uarte = unsafe { &*T::ptr() }; + + compiler_fence(SeqCst); + + // This complexity to handle in-progress reads is needed because calls to this read method + // might be interleaved with calls to serial::Read::read. + + // If no read transaction is started yet, start one and wait for it to start. + if uarte.events_rxstarted.read().bits() == 0 { + start_read(&uarte, self.rx_buf)?; + } + + // Wait for the transaction to finish. + while uarte.events_endrx.read().bits() == 0 { + spin_loop(); + } + + // Tidy up and return the byte read. + uarte.events_rxstarted.reset(); + finalize_read(uarte); + if uarte.rxd.amount.read().bits() != 1 { + return Err(Error::Receive); + } + buf[0] = self.rx_buf[0]; + Ok(1) + } +} + impl serial::Read for UarteRx where T: Instance, @@ -768,7 +884,7 @@ where finalize_read(uarte); - if uarte.rxd.amount.read().bits() != 1 as u32 { + if uarte.rxd.amount.read().bits() != 1 { return Err(nb::Error::Other(Error::Receive)); } Ok(self.rx_buf[0]) From a2f7254c6aeb0e78468e4ffcabc999ee8051a25a Mon Sep 17 00:00:00 2001 From: Andrew Walbran Date: Tue, 6 Feb 2024 14:24:03 +0000 Subject: [PATCH 10/10] Fix calculation for DelayNs. Use u64 for intermediate value to avoid overflow. --- nrf-hal-common/src/delay.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/nrf-hal-common/src/delay.rs b/nrf-hal-common/src/delay.rs index 19090234..269f63d6 100644 --- a/nrf-hal-common/src/delay.rs +++ b/nrf-hal-common/src/delay.rs @@ -1,8 +1,9 @@ //! Delays. -use cortex_m::peripheral::syst::SystClkSource; -use cortex_m::peripheral::SYST; use crate::clocks::HFCLK_FREQ; +use core::convert::TryInto; +use cortex_m::peripheral::syst::SystClkSource; +use cortex_m::peripheral::SYST; use embedded_hal::delay::DelayNs; use embedded_hal_02::blocking::delay::{DelayMs, DelayUs}; @@ -66,7 +67,9 @@ impl DelayNs for Delay { // The SysTick Reload Value register supports values between 1 and 0x00FFFFFF. const MAX_RVR: u32 = 0x00FF_FFFF; - let mut total_rvr = ns * (HFCLK_FREQ / 1_000_000_000); + let mut total_rvr: u32 = (u64::from(ns) * u64::from(HFCLK_FREQ) / 1_000_000_000) + .try_into() + .unwrap(); while total_rvr != 0 { let current_rvr = if total_rvr <= MAX_RVR {