Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Rename DelayUs to BasicDelay, add delay_ns. #537

Merged
merged 3 commits into from
Nov 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions embedded-hal-async/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/).

- Minor document fixes.
- Add #[inline] hints to most of `embedded-hal-async` functions.
- delay: Rename `DelayUs` to `DelayNs`
- delay: Add `DelayNs::delay_ns()`
- delay: Add default impls of `delay_ms` and `delay_us` based on `delay_ns`.
- spi: Rename `Operation::DelayUs` to `Operation::DelayNs`, with nanosecond precision.

## [v1.0.0-rc.1] - 2023-08-15

Expand Down
34 changes: 28 additions & 6 deletions embedded-hal-async/src/delay.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,42 @@
//! Delays.

/// Microsecond delay.
pub trait DelayUs {
/// Delay with up to nanosecond precision.
pub trait DelayNs {
/// Pauses execution for at minimum `ns` nanoseconds. Pause can be longer
/// if the implementation requires it due to precision/timing issues.
async fn delay_ns(&mut self, ns: u32);

/// Pauses execution for at minimum `us` microseconds. Pause can be longer
/// if the implementation requires it due to precision/timing issues.
async fn delay_us(&mut self, us: u32);
async fn delay_us(&mut self, mut us: u32) {
while us > 4_294_967 {
us -= 4_294_967;
self.delay_ns(4_294_967_000).await;
}
self.delay_ns(us * 1_000).await;
}

/// Pauses execution for at minimum `ms` milliseconds. Pause can be longer
/// if the implementation requires it due to precision/timing issues.
async fn delay_ms(&mut self, ms: u32);
#[inline]
async fn delay_ms(&mut self, mut ms: u32) {
while ms > 4294 {
ms -= 4294;
self.delay_ns(4_294_000_000).await;
}
self.delay_ns(ms * 1_000_000).await;
}
}

impl<T> DelayUs for &mut T
impl<T> DelayNs for &mut T
where
T: DelayUs + ?Sized,
T: DelayNs + ?Sized,
{
#[inline]
async fn delay_ns(&mut self, ns: u32) {
T::delay_ns(self, ns).await;
}

#[inline]
async fn delay_us(&mut self, us: u32) {
T::delay_us(self, us).await;
Expand Down
6 changes: 3 additions & 3 deletions embedded-hal-bus/src/spi/critical_section.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use core::cell::RefCell;
use critical_section::Mutex;
use embedded_hal::delay::DelayUs;
use embedded_hal::delay::DelayNs;
use embedded_hal::digital::OutputPin;
use embedded_hal::spi::{ErrorType, Operation, SpiBus, SpiDevice};

Expand Down Expand Up @@ -37,7 +37,7 @@ impl<'a, BUS, CS> CriticalSectionDevice<'a, BUS, CS, super::NoDelay> {
/// # Panics
///
/// The returned device will panic if you try to execute a transaction
/// that contains any operations of type [`Operation::DelayUs`].
/// that contains any operations of type [`Operation::DelayNs`].
#[inline]
pub fn new_no_delay(bus: &'a Mutex<RefCell<BUS>>, cs: CS) -> Self {
Self {
Expand All @@ -60,7 +60,7 @@ impl<'a, Word: Copy + 'static, BUS, CS, D> SpiDevice<Word> for CriticalSectionDe
where
BUS: SpiBus<Word>,
CS: OutputPin,
D: DelayUs,
D: DelayNs,
{
#[inline]
fn transaction(&mut self, operations: &mut [Operation<'_, Word>]) -> Result<(), Self::Error> {
Expand Down
39 changes: 9 additions & 30 deletions embedded-hal-bus/src/spi/exclusive.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
//! SPI bus sharing mechanisms.

use embedded_hal::delay::DelayUs;
use embedded_hal::delay::DelayNs;
use embedded_hal::digital::OutputPin;
use embedded_hal::spi::{ErrorType, Operation, SpiBus, SpiDevice};
#[cfg(feature = "async")]
use embedded_hal_async::{
delay::DelayUs as AsyncDelayUs,
delay::DelayNs as AsyncDelayNs,
spi::{SpiBus as AsyncSpiBus, SpiDevice as AsyncSpiDevice},
};

use super::shared::transaction;
use super::DeviceError;

/// [`SpiDevice`] implementation with exclusive access to the bus (not shared).
Expand Down Expand Up @@ -47,7 +48,7 @@ impl<BUS, CS> ExclusiveDevice<BUS, CS, super::NoDelay> {
/// # Panics
///
/// The returned device will panic if you try to execute a transaction
/// that contains any operations of type `Operation::DelayUs`.
/// that contains any operations of type [`Operation::DelayNs`].
#[inline]
pub fn new_no_delay(bus: BUS, cs: CS) -> Self {
Self {
Expand All @@ -70,33 +71,11 @@ impl<Word: Copy + 'static, BUS, CS, D> SpiDevice<Word> for ExclusiveDevice<BUS,
where
BUS: SpiBus<Word>,
CS: OutputPin,
D: DelayUs,
D: DelayNs,
{
#[inline]
fn transaction(&mut self, operations: &mut [Operation<'_, Word>]) -> Result<(), Self::Error> {
self.cs.set_low().map_err(DeviceError::Cs)?;

let op_res = operations.iter_mut().try_for_each(|op| match op {
Operation::Read(buf) => self.bus.read(buf),
Operation::Write(buf) => self.bus.write(buf),
Operation::Transfer(read, write) => self.bus.transfer(read, write),
Operation::TransferInPlace(buf) => self.bus.transfer_in_place(buf),
Operation::DelayUs(us) => {
self.bus.flush()?;
self.delay.delay_us(*us);
Ok(())
}
});

// On failure, it's important to still flush and deassert CS.
let flush_res = self.bus.flush();
let cs_res = self.cs.set_high();

op_res.map_err(DeviceError::Spi)?;
flush_res.map_err(DeviceError::Spi)?;
cs_res.map_err(DeviceError::Cs)?;

Ok(())
transaction(operations, &mut self.bus, &mut self.delay, &mut self.cs)
}
}

Expand All @@ -106,7 +85,7 @@ impl<Word: Copy + 'static, BUS, CS, D> AsyncSpiDevice<Word> for ExclusiveDevice<
where
BUS: AsyncSpiBus<Word>,
CS: OutputPin,
D: AsyncDelayUs,
D: AsyncDelayNs,
{
#[inline]
async fn transaction(
Expand All @@ -122,10 +101,10 @@ where
Operation::Write(buf) => self.bus.write(buf).await,
Operation::Transfer(read, write) => self.bus.transfer(read, write).await,
Operation::TransferInPlace(buf) => self.bus.transfer_in_place(buf).await,
Operation::DelayUs(us) => match self.bus.flush().await {
Operation::DelayNs(ns) => match self.bus.flush().await {
Err(e) => Err(e),
Ok(()) => {
self.delay.delay_us(*us).await;
self.delay.delay_ns(*ns).await;
Ok(())
}
},
Expand Down
17 changes: 6 additions & 11 deletions embedded-hal-bus/src/spi/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,33 +43,28 @@ where
}
}

/// Dummy `DelayUs` implementation that panics on use.
/// Dummy [`DelayNs`](embedded_hal::delay::DelayNs) implementation that panics on use.
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
#[cfg_attr(feature = "defmt-03", derive(defmt::Format))]
pub struct NoDelay;

#[cold]
fn no_delay_panic() {
panic!("You've tried to execute a SPI transaction containing a `Operation::Delay` in a `SpiDevice` created with `new_no_delay()`. Create it with `new()` instead, passing a `DelayUs` implementation.");
panic!("You've tried to execute a SPI transaction containing a `Operation::DelayNs` in a `SpiDevice` created with `new_no_delay()`. Create it with `new()` instead, passing a `DelayNs` implementation.");
}

impl embedded_hal::delay::DelayUs for NoDelay {
impl embedded_hal::delay::DelayNs for NoDelay {
#[inline]
fn delay_us(&mut self, _us: u32) {
fn delay_ns(&mut self, _ns: u32) {
no_delay_panic();
}
}

#[cfg(feature = "async")]
#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
impl embedded_hal_async::delay::DelayUs for NoDelay {
impl embedded_hal_async::delay::DelayNs for NoDelay {
#[inline]
async fn delay_us(&mut self, _us: u32) {
no_delay_panic();
}

#[inline]
async fn delay_ms(&mut self, _ms: u32) {
async fn delay_ns(&mut self, _ns: u32) {
no_delay_panic();
}
}
6 changes: 3 additions & 3 deletions embedded-hal-bus/src/spi/mutex.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use embedded_hal::delay::DelayUs;
use embedded_hal::delay::DelayNs;
use embedded_hal::digital::OutputPin;
use embedded_hal::spi::{ErrorType, Operation, SpiBus, SpiDevice};
use std::sync::Mutex;
Expand Down Expand Up @@ -35,7 +35,7 @@ impl<'a, BUS, CS> MutexDevice<'a, BUS, CS, super::NoDelay> {
/// # Panics
///
/// The returned device will panic if you try to execute a transaction
/// that contains any operations of type `Operation::DelayUs`.
/// that contains any operations of type [`Operation::DelayNs`].
#[inline]
pub fn new_no_delay(bus: &'a Mutex<BUS>, cs: CS) -> Self {
Self {
Expand All @@ -58,7 +58,7 @@ impl<'a, Word: Copy + 'static, BUS, CS, D> SpiDevice<Word> for MutexDevice<'a, B
where
BUS: SpiBus<Word>,
CS: OutputPin,
D: DelayUs,
D: DelayNs,
{
#[inline]
fn transaction(&mut self, operations: &mut [Operation<'_, Word>]) -> Result<(), Self::Error> {
Expand Down
6 changes: 3 additions & 3 deletions embedded-hal-bus/src/spi/refcell.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use core::cell::RefCell;
use embedded_hal::delay::DelayUs;
use embedded_hal::delay::DelayNs;
use embedded_hal::digital::OutputPin;
use embedded_hal::spi::{ErrorType, Operation, SpiBus, SpiDevice};

Expand Down Expand Up @@ -34,7 +34,7 @@ impl<'a, BUS, CS> RefCellDevice<'a, BUS, CS, super::NoDelay> {
/// # Panics
///
/// The returned device will panic if you try to execute a transaction
/// that contains any operations of type `Operation::DelayUs`.
/// that contains any operations of type [`Operation::DelayNs`].
#[inline]
pub fn new_no_delay(bus: &'a RefCell<BUS>, cs: CS) -> Self {
Self {
Expand All @@ -57,7 +57,7 @@ impl<'a, Word: Copy + 'static, BUS, CS, D> SpiDevice<Word> for RefCellDevice<'a,
where
BUS: SpiBus<Word>,
CS: OutputPin,
D: DelayUs,
D: DelayNs,
{
#[inline]
fn transaction(&mut self, operations: &mut [Operation<'_, Word>]) -> Result<(), Self::Error> {
Expand Down
8 changes: 4 additions & 4 deletions embedded-hal-bus/src/spi/shared.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use embedded_hal::delay::DelayUs;
use embedded_hal::delay::DelayNs;
use embedded_hal::digital::OutputPin;
use embedded_hal::spi::{ErrorType, Operation, SpiBus};

Expand All @@ -15,7 +15,7 @@ pub fn transaction<Word, BUS, CS, D>(
where
BUS: SpiBus<Word> + ErrorType,
CS: OutputPin,
D: DelayUs,
D: DelayNs,
Word: Copy,
{
cs.set_low().map_err(DeviceError::Cs)?;
Expand All @@ -25,9 +25,9 @@ where
Operation::Write(buf) => bus.write(buf),
Operation::Transfer(read, write) => bus.transfer(read, write),
Operation::TransferInPlace(buf) => bus.transfer_in_place(buf),
Operation::DelayUs(us) => {
Operation::DelayNs(ns) => {
bus.flush()?;
delay.delay_us(*us);
delay.delay_ns(*ns);
Ok(())
}
});
Expand Down
5 changes: 5 additions & 0 deletions embedded-hal/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- Minor document fixes.
- Add #[inline] hints to most of `embedded-hal` functions.
- pwm: rename `get_max_duty_cycle` to `max_duty_cycle`.
- delay: Rename `DelayUs` to `DelayNs`
- delay: Add `DelayNs::delay_ns()`
- delay: Add default impls of `delay_ms` and `delay_us` based on `delay_ns`.
- delay: Make the default impl of `delay_ms` more efficient, it now does less calls to the underlying `delay_ns` (previously `delay_us`).
- spi: Rename `Operation::DelayUs` to `Operation::DelayNs`, with nanosecond precision.

## [v1.0.0-rc.1] - 2023-08-15

Expand Down
33 changes: 25 additions & 8 deletions embedded-hal/src/delay.rs
Original file line number Diff line number Diff line change
@@ -1,25 +1,42 @@
//! Delays.

/// Microsecond delay.
pub trait DelayUs {
/// Delay with up to nanosecond precision.
pub trait DelayNs {
/// Pauses execution for at minimum `ns` nanoseconds. Pause can be longer
/// if the implementation requires it due to precision/timing issues.
fn delay_ns(&mut self, ns: u32);

/// Pauses execution for at minimum `us` microseconds. Pause can be longer
/// if the implementation requires it due to precision/timing issues.
fn delay_us(&mut self, us: u32);
fn delay_us(&mut self, mut us: u32) {
while us > 4_294_967 {
us -= 4_294_967;
self.delay_ns(4_294_967_000);
}
self.delay_ns(us * 1_000);
}

/// Pauses execution for at minimum `ms` milliseconds. Pause can be longer
/// if the implementation requires it due to precision/timing issues.
#[inline]
fn delay_ms(&mut self, ms: u32) {
for _ in 0..ms {
self.delay_us(1000);
fn delay_ms(&mut self, mut ms: u32) {
while ms > 4294 {
ms -= 4294;
self.delay_ns(4_294_000_000);
}
self.delay_ns(ms * 1_000_000);
}
}

impl<T> DelayUs for &mut T
impl<T> DelayNs for &mut T
where
T: DelayUs + ?Sized,
T: DelayNs + ?Sized,
{
#[inline]
fn delay_ns(&mut self, ns: u32) {
T::delay_ns(self, ns);
}

#[inline]
fn delay_us(&mut self, us: u32) {
T::delay_us(self, us);
Expand Down
4 changes: 2 additions & 2 deletions embedded-hal/src/spi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -324,8 +324,8 @@ pub enum Operation<'a, Word: 'static> {
///
/// Equivalent to [`SpiBus::transfer_in_place`].
TransferInPlace(&'a mut [Word]),
/// Delay for at least the specified number of microseconds.
DelayUs(u32),
/// Delay for at least the specified number of nanoseconds.
DelayNs(u32),
}

/// SPI device trait.
Expand Down