From 4032fc06556312eab27488f05efe1803ade47b45 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Wed, 26 Jan 2022 22:39:06 +0100 Subject: [PATCH 1/2] Support unstable-trait feature for stm32 --- embassy-lora/Cargo.toml | 2 + embassy-lora/src/sx127x/mod.rs | 24 +- embassy-lora/src/sx127x/sx127x_lora/mod.rs | 9 +- embassy-stm32/Cargo.toml | 9 +- embassy-stm32/src/adc/f1.rs | 2 +- embassy-stm32/src/adc/v3.rs | 2 +- embassy-stm32/src/exti.rs | 119 +++++----- embassy-stm32/src/gpio.rs | 2 +- embassy-stm32/src/i2c/mod.rs | 1 + embassy-stm32/src/i2c/v1.rs | 6 +- embassy-stm32/src/i2c/v2.rs | 142 ++++++++---- embassy-stm32/src/spi/mod.rs | 210 +++++++++++++----- embassy-stm32/src/usart/mod.rs | 146 +++++++----- embassy-traits/Cargo.toml | 4 +- embassy-traits/src/adapter.rs | 206 ++++++++++++----- embassy-traits/src/gpio.rs | 57 ----- embassy-traits/src/i2c.rs | 192 ---------------- embassy-traits/src/lib.rs | 4 - embassy-traits/src/spi.rs | 61 ----- embassy-traits/src/uart.rs | 36 --- examples/stm32f3/src/bin/spi_dma.rs | 3 +- examples/stm32h7/Cargo.toml | 3 +- examples/stm32h7/src/bin/camera.rs | 2 +- examples/stm32h7/src/bin/spi_dma.rs | 5 +- examples/stm32l0/Cargo.toml | 2 +- examples/stm32l4/Cargo.toml | 3 +- .../stm32l4/src/bin/i2c_blocking_async.rs | 3 +- .../stm32l4/src/bin/spi_blocking_async.rs | 9 +- examples/stm32l4/src/bin/spi_dma.rs | 3 +- .../stm32l4/src/bin/usart_blocking_async.rs | 6 +- tests/stm32/Cargo.toml | 1 + tests/stm32/src/bin/spi_dma.rs | 3 +- 32 files changed, 604 insertions(+), 673 deletions(-) delete mode 100644 embassy-traits/src/gpio.rs delete mode 100644 embassy-traits/src/i2c.rs delete mode 100644 embassy-traits/src/spi.rs delete mode 100644 embassy-traits/src/uart.rs diff --git a/embassy-lora/Cargo.toml b/embassy-lora/Cargo.toml index 9f04adabb..c27641521 100644 --- a/embassy-lora/Cargo.toml +++ b/embassy-lora/Cargo.toml @@ -18,6 +18,8 @@ log = { version = "0.4.14", optional = true } embassy = { version = "0.1.0", path = "../embassy", default-features = false } embassy-stm32 = { version = "0.1.0", path = "../embassy-stm32", default-features = false, optional = true } +embedded-hal-1 = { package = "embedded-hal", version = "1.0.0-alpha.6", git = "https://github.com/embassy-rs/embedded-hal", branch = "embassy", optional = true} +embedded-hal-async = { version = "0.0.1", git = "https://github.com/embassy-rs/embedded-hal", branch = "embassy"} embassy-hal-common = { version = "0.1.0", path = "../embassy-hal-common", default-features = false } futures = { version = "0.3.17", default-features = false, features = [ "async-await" ] } embedded-hal = { version = "0.2", features = ["unproven"] } diff --git a/embassy-lora/src/sx127x/mod.rs b/embassy-lora/src/sx127x/mod.rs index c26628b0f..6a15dab82 100644 --- a/embassy-lora/src/sx127x/mod.rs +++ b/embassy-lora/src/sx127x/mod.rs @@ -1,7 +1,7 @@ use core::future::Future; -use embassy::traits::gpio::WaitForRisingEdge; -use embassy::traits::spi::*; use embedded_hal::digital::v2::OutputPin; +use embedded_hal_async::digital::Wait; +use embedded_hal_async::spi::*; use lorawan_device::async_device::{ radio::{Bandwidth, PhyRxTx, RfConfig, RxQuality, SpreadingFactor, TxConfig}, Timings, @@ -20,11 +20,11 @@ pub trait RadioSwitch { /// Semtech Sx127x radio peripheral pub struct Sx127xRadio where - SPI: FullDuplex + 'static, + SPI: ReadWrite + 'static, E: 'static, CS: OutputPin + 'static, RESET: OutputPin + 'static, - I: WaitForRisingEdge + 'static, + I: Wait + 'static, RFS: RadioSwitch + 'static, { radio: LoRa, @@ -42,10 +42,10 @@ pub enum State { impl Sx127xRadio where - SPI: FullDuplex + 'static, + SPI: ReadWrite + 'static, CS: OutputPin + 'static, RESET: OutputPin + 'static, - I: WaitForRisingEdge + 'static, + I: Wait + 'static, RFS: RadioSwitch + 'static, E: 'static, { @@ -64,10 +64,10 @@ where impl Timings for Sx127xRadio where - SPI: FullDuplex + 'static, + SPI: ReadWrite + 'static, CS: OutputPin + 'static, RESET: OutputPin + 'static, - I: WaitForRisingEdge + 'static, + I: Wait + 'static, RFS: RadioSwitch + 'static, { fn get_rx_window_offset_ms(&self) -> i32 { @@ -80,11 +80,11 @@ where impl PhyRxTx for Sx127xRadio where - SPI: FullDuplex + 'static, + SPI: ReadWrite + 'static, CS: OutputPin + 'static, E: 'static, RESET: OutputPin + 'static, - I: WaitForRisingEdge + 'static, + I: Wait + 'static, RFS: RadioSwitch + 'static, { type PhyError = Sx127xError; @@ -126,7 +126,7 @@ where self.radio.transmit_start(buf).await?; loop { - self.irq.wait_for_rising_edge().await; + self.irq.wait_for_rising_edge().await.unwrap(); self.radio.set_mode(RadioMode::Stdby).await.ok().unwrap(); let irq = self.radio.clear_irq().await.ok().unwrap(); if (irq & IRQ::IrqTxDoneMask.addr()) != 0 { @@ -171,7 +171,7 @@ where self.radio.set_mode(RadioMode::RxContinuous).await?; loop { - self.irq.wait_for_rising_edge().await; + self.irq.wait_for_rising_edge().await.unwrap(); self.radio.set_mode(RadioMode::Stdby).await.ok().unwrap(); let irq = self.radio.clear_irq().await.ok().unwrap(); if (irq & IRQ::IrqRxDoneMask.addr()) != 0 { diff --git a/embassy-lora/src/sx127x/sx127x_lora/mod.rs b/embassy-lora/src/sx127x/sx127x_lora/mod.rs index a903779ca..6fbd3a4bd 100644 --- a/embassy-lora/src/sx127x/sx127x_lora/mod.rs +++ b/embassy-lora/src/sx127x/sx127x_lora/mod.rs @@ -7,8 +7,8 @@ use bit_field::BitField; use embassy::time::{Duration, Timer}; -use embassy::traits::spi::*; use embedded_hal::digital::v2::OutputPin; +use embedded_hal_async::spi::ReadWrite; mod register; use self::register::PaConfig; @@ -36,9 +36,10 @@ pub enum Error { Transmitting, } -use super::sx127x_lora::register::{FskDataModulationShaping, FskRampUpRamDown}; use Error::*; +use super::sx127x_lora::register::{FskDataModulationShaping, FskRampUpRamDown}; + #[cfg(not(feature = "version_0x09"))] const VERSION_CHECK: u8 = 0x12; @@ -47,7 +48,7 @@ const VERSION_CHECK: u8 = 0x09; impl LoRa where - SPI: FullDuplex, + SPI: ReadWrite, CS: OutputPin, RESET: OutputPin, { @@ -546,7 +547,7 @@ where let _ = self .spi - .read_write(&mut buffer, &[reg & 0x7f, 0]) + .transfer(&mut buffer, &[reg & 0x7f, 0]) .await .map_err(SPI)?; diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 6f9b2043f..e0fd1d963 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -9,14 +9,16 @@ resolver = "2" embassy = { version = "0.1.0", path = "../embassy" } embassy-macros = { version = "0.1.0", path = "../embassy-macros", features = ["stm32"] } embassy-hal-common = {version = "0.1.0", path = "../embassy-hal-common" } -embassy-traits = {version = "0.1.0", path = "../embassy-traits" } embassy-net = { version = "0.1.0", path = "../embassy-net", default-features = false, optional = true } +embedded-hal-02 = { package = "embedded-hal", version = "0.2.6" } +embedded-hal-1 = { package = "embedded-hal", version = "1.0.0-alpha.6", git = "https://github.com/embassy-rs/embedded-hal", branch = "embassy", optional = true} +embedded-hal-async = { version = "0.0.1", git = "https://github.com/embassy-rs/embedded-hal", branch = "embassy", optional = true} + defmt = { version = "0.3", optional = true } log = { version = "0.4.14", optional = true } cortex-m-rt = ">=0.6.15,<0.8" cortex-m = "0.7.3" -embedded-hal = { version = "0.2.6", features = ["unproven"] } futures = { version = "0.3.17", default-features = false, features = ["async-await"] } rand_core = "0.6.3" sdio-host = "0.5.0" @@ -56,6 +58,9 @@ time-driver-tim5 = ["_time-driver"] # There are no plans to make this stable. unstable-pac = [] +# Implement embedded-hal 1.0 alpha and embedded-hal-async traits. +unstable-traits = ["embedded-hal-1", "embedded-hal-async"] + # BEGIN GENERATED FEATURES # Generated by stm32-gen-features. DO NOT EDIT. stm32f030c6 = [ "stm32-metapac/stm32f030c6" ] diff --git a/embassy-stm32/src/adc/f1.rs b/embassy-stm32/src/adc/f1.rs index 3ed1701fa..6031883ec 100644 --- a/embassy-stm32/src/adc/f1.rs +++ b/embassy-stm32/src/adc/f1.rs @@ -4,7 +4,7 @@ use crate::time::Hertz; use core::marker::PhantomData; use embassy::util::Unborrow; use embassy_hal_common::unborrow; -use embedded_hal::blocking::delay::DelayUs; +use embedded_hal_02::blocking::delay::DelayUs; pub const VDDA_CALIB_MV: u32 = 3300; pub const ADC_MAX: u32 = (1 << 12) - 1; diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs index ddf06deae..6f36daa23 100644 --- a/embassy-stm32/src/adc/v3.rs +++ b/embassy-stm32/src/adc/v3.rs @@ -2,7 +2,7 @@ use crate::adc::{AdcPin, Instance}; use core::marker::PhantomData; use embassy::util::Unborrow; use embassy_hal_common::unborrow; -use embedded_hal::blocking::delay::DelayUs; +use embedded_hal_02::blocking::delay::DelayUs; pub const VDDA_CALIB_MV: u32 = 3000; diff --git a/embassy-stm32/src/exti.rs b/embassy-stm32/src/exti.rs index af401796c..7d974c2dc 100644 --- a/embassy-stm32/src/exti.rs +++ b/embassy-stm32/src/exti.rs @@ -1,15 +1,10 @@ -use core::convert::Infallible; use core::future::Future; use core::marker::PhantomData; use core::pin::Pin; use core::task::{Context, Poll}; -use embassy::traits::gpio::{ - WaitForAnyEdge, WaitForFallingEdge, WaitForHigh, WaitForLow, WaitForRisingEdge, -}; use embassy::util::Unborrow; use embassy::waitqueue::AtomicWaker; use embassy_hal_common::unsafe_impl_unborrow; -use embedded_hal::digital::v2::InputPin; use crate::gpio::{AnyPin, Input, Pin as GpioPin}; use crate::interrupt; @@ -134,70 +129,88 @@ impl<'d, T: GpioPin> ExtiInput<'d, T> { } } -impl<'d, T: GpioPin> InputPin for ExtiInput<'d, T> { - type Error = Infallible; +mod eh02 { + use super::*; + use core::convert::Infallible; - fn is_high(&self) -> Result { - Ok(self.is_high()) - } + impl<'d, T: GpioPin> embedded_hal_02::digital::v2::InputPin for ExtiInput<'d, T> { + type Error = Infallible; - fn is_low(&self) -> Result { - Ok(self.is_low()) + fn is_high(&self) -> Result { + Ok(self.is_high()) + } + + fn is_low(&self) -> Result { + Ok(self.is_low()) + } } } -impl<'d, T: GpioPin> WaitForHigh for ExtiInput<'d, T> { - type Future<'a> - where - Self: 'a, - = impl Future + 'a; +#[cfg(feature = "unstable-traits")] +mod eh1 { + use super::*; + use core::convert::Infallible; + use futures::FutureExt; - fn wait_for_high<'a>(&'a mut self) -> Self::Future<'a> { - self.wait_for_high() + impl<'d, T: GpioPin> embedded_hal_1::digital::ErrorType for ExtiInput<'d, T> { + type Error = Infallible; } -} -impl<'d, T: GpioPin> WaitForLow for ExtiInput<'d, T> { - type Future<'a> - where - Self: 'a, - = impl Future + 'a; + impl<'d, T: GpioPin> embedded_hal_1::digital::blocking::InputPin for ExtiInput<'d, T> { + fn is_high(&self) -> Result { + Ok(self.is_high()) + } - fn wait_for_low<'a>(&'a mut self) -> Self::Future<'a> { - self.wait_for_low() + fn is_low(&self) -> Result { + Ok(self.is_low()) + } } -} -impl<'d, T: GpioPin> WaitForRisingEdge for ExtiInput<'d, T> { - type Future<'a> - where - Self: 'a, - = impl Future + 'a; + impl<'d, T: GpioPin> embedded_hal_async::digital::Wait for ExtiInput<'d, T> { + type WaitForHighFuture<'a> + where + Self: 'a, + = impl Future> + 'a; - fn wait_for_rising_edge<'a>(&'a mut self) -> Self::Future<'a> { - self.wait_for_rising_edge() - } -} + fn wait_for_high<'a>(&'a mut self) -> Self::WaitForHighFuture<'a> { + self.wait_for_high().map(Ok) + } -impl<'d, T: GpioPin> WaitForFallingEdge for ExtiInput<'d, T> { - type Future<'a> - where - Self: 'a, - = impl Future + 'a; + type WaitForLowFuture<'a> + where + Self: 'a, + = impl Future> + 'a; - fn wait_for_falling_edge<'a>(&'a mut self) -> Self::Future<'a> { - self.wait_for_falling_edge() - } -} + fn wait_for_low<'a>(&'a mut self) -> Self::WaitForLowFuture<'a> { + self.wait_for_low().map(Ok) + } -impl<'d, T: GpioPin> WaitForAnyEdge for ExtiInput<'d, T> { - type Future<'a> - where - Self: 'a, - = impl Future + 'a; + type WaitForRisingEdgeFuture<'a> + where + Self: 'a, + = impl Future> + 'a; - fn wait_for_any_edge<'a>(&'a mut self) -> Self::Future<'a> { - self.wait_for_any_edge() + fn wait_for_rising_edge<'a>(&'a mut self) -> Self::WaitForRisingEdgeFuture<'a> { + self.wait_for_rising_edge().map(Ok) + } + + type WaitForFallingEdgeFuture<'a> + where + Self: 'a, + = impl Future> + 'a; + + fn wait_for_falling_edge<'a>(&'a mut self) -> Self::WaitForFallingEdgeFuture<'a> { + self.wait_for_falling_edge().map(Ok) + } + + type WaitForAnyEdgeFuture<'a> + where + Self: 'a, + = impl Future> + 'a; + + fn wait_for_any_edge<'a>(&'a mut self) -> Self::WaitForAnyEdgeFuture<'a> { + self.wait_for_any_edge().map(Ok) + } } } diff --git a/embassy-stm32/src/gpio.rs b/embassy-stm32/src/gpio.rs index 57b9ba6b7..d4606716c 100644 --- a/embassy-stm32/src/gpio.rs +++ b/embassy-stm32/src/gpio.rs @@ -3,7 +3,7 @@ use core::convert::Infallible; use core::marker::PhantomData; use embassy::util::Unborrow; use embassy_hal_common::{unborrow, unsafe_impl_unborrow}; -use embedded_hal::digital::v2::{InputPin, OutputPin, StatefulOutputPin, ToggleableOutputPin}; +use embedded_hal_02::digital::v2::{InputPin, OutputPin, StatefulOutputPin, ToggleableOutputPin}; use crate::pac; use crate::pac::gpio::{self, vals}; diff --git a/embassy-stm32/src/i2c/mod.rs b/embassy-stm32/src/i2c/mod.rs index 8eee13825..2dcb9b720 100644 --- a/embassy-stm32/src/i2c/mod.rs +++ b/embassy-stm32/src/i2c/mod.rs @@ -8,6 +8,7 @@ mod _version; use crate::{dma, peripherals}; pub use _version::*; +#[derive(Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum Error { Bus, diff --git a/embassy-stm32/src/i2c/v1.rs b/embassy-stm32/src/i2c/v1.rs index 6b2c8a35c..aa5268987 100644 --- a/embassy-stm32/src/i2c/v1.rs +++ b/embassy-stm32/src/i2c/v1.rs @@ -270,7 +270,7 @@ impl<'d, T: Instance> I2c<'d, T> { } } -impl<'d, T: Instance> embedded_hal::blocking::i2c::Read for I2c<'d, T> { +impl<'d, T: Instance> embedded_hal_02::blocking::i2c::Read for I2c<'d, T> { type Error = Error; fn read(&mut self, addr: u8, buffer: &mut [u8]) -> Result<(), Self::Error> { @@ -278,7 +278,7 @@ impl<'d, T: Instance> embedded_hal::blocking::i2c::Read for I2c<'d, T> { } } -impl<'d, T: Instance> embedded_hal::blocking::i2c::Write for I2c<'d, T> { +impl<'d, T: Instance> embedded_hal_02::blocking::i2c::Write for I2c<'d, T> { type Error = Error; fn write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Self::Error> { @@ -286,7 +286,7 @@ impl<'d, T: Instance> embedded_hal::blocking::i2c::Write for I2c<'d, T> { } } -impl<'d, T: Instance> embedded_hal::blocking::i2c::WriteRead for I2c<'d, T> { +impl<'d, T: Instance> embedded_hal_02::blocking::i2c::WriteRead for I2c<'d, T> { type Error = Error; fn write_read(&mut self, addr: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Self::Error> { diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs index 5b0e5fce2..9c05187a5 100644 --- a/embassy-stm32/src/i2c/v2.rs +++ b/embassy-stm32/src/i2c/v2.rs @@ -1,11 +1,9 @@ use core::cmp; -use core::future::Future; use core::marker::PhantomData; use core::task::Poll; use atomic_polyfill::{AtomicUsize, Ordering}; use embassy::interrupt::InterruptExt; -use embassy::traits::i2c::I2c as I2cTrait; use embassy::util::Unborrow; use embassy::waitqueue::AtomicWaker; use embassy_hal_common::drop::OnDrop; @@ -735,32 +733,36 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { } } -impl<'d, T: Instance> embedded_hal::blocking::i2c::Read for I2c<'d, T> { - type Error = Error; +mod eh02 { + use super::*; - fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> { - self.blocking_read(address, buffer) + impl<'d, T: Instance> embedded_hal_02::blocking::i2c::Read for I2c<'d, T> { + type Error = Error; + + fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> { + self.blocking_read(address, buffer) + } } -} -impl<'d, T: Instance> embedded_hal::blocking::i2c::Write for I2c<'d, T> { - type Error = Error; + impl<'d, T: Instance> embedded_hal_02::blocking::i2c::Write for I2c<'d, T> { + type Error = Error; - fn write(&mut self, address: u8, bytes: &[u8]) -> Result<(), Self::Error> { - self.blocking_write(address, bytes) + fn write(&mut self, address: u8, bytes: &[u8]) -> Result<(), Self::Error> { + self.blocking_write(address, bytes) + } } -} -impl<'d, T: Instance> embedded_hal::blocking::i2c::WriteRead for I2c<'d, T> { - type Error = Error; + impl<'d, T: Instance> embedded_hal_02::blocking::i2c::WriteRead for I2c<'d, T> { + type Error = Error; - fn write_read( - &mut self, - address: u8, - bytes: &[u8], - buffer: &mut [u8], - ) -> Result<(), Self::Error> { - self.blocking_write_read(address, bytes, buffer) + fn write_read( + &mut self, + address: u8, + bytes: &[u8], + buffer: &mut [u8], + ) -> Result<(), Self::Error> { + self.blocking_write_read(address, bytes, buffer) + } } } @@ -906,38 +908,80 @@ impl Timings { } } -impl<'d, T: Instance, TXDMA: super::TxDma, RXDMA: super::RxDma> I2cTrait - for I2c<'d, T, TXDMA, RXDMA> -{ - type Error = super::Error; +#[cfg(feature = "unstable-traits")] +mod eh1 { + use super::super::{RxDma, TxDma}; + use super::*; + use core::future::Future; - type WriteFuture<'a> - where - Self: 'a, - = impl Future> + 'a; - type ReadFuture<'a> - where - Self: 'a, - = impl Future> + 'a; - type WriteReadFuture<'a> - where - Self: 'a, - = impl Future> + 'a; - - fn read<'a>(&'a mut self, address: u8, buffer: &'a mut [u8]) -> Self::ReadFuture<'a> { - self.read(address, buffer) + impl embedded_hal_1::i2c::Error for Error { + fn kind(&self) -> embedded_hal_1::i2c::ErrorKind { + match *self { + Self::Bus => embedded_hal_1::i2c::ErrorKind::Bus, + Self::Arbitration => embedded_hal_1::i2c::ErrorKind::ArbitrationLoss, + Self::Nack => embedded_hal_1::i2c::ErrorKind::NoAcknowledge( + embedded_hal_1::i2c::NoAcknowledgeSource::Unknown, + ), + Self::Timeout => embedded_hal_1::i2c::ErrorKind::Other, + Self::Crc => embedded_hal_1::i2c::ErrorKind::Other, + Self::Overrun => embedded_hal_1::i2c::ErrorKind::Overrun, + Self::ZeroLengthTransfer => embedded_hal_1::i2c::ErrorKind::Other, + } + } } - fn write<'a>(&'a mut self, address: u8, bytes: &'a [u8]) -> Self::WriteFuture<'a> { - self.write(address, bytes) + impl<'d, T: Instance, TXDMA: TxDma, RXDMA: RxDma> embedded_hal_1::i2c::ErrorType + for I2c<'d, T, TXDMA, RXDMA> + { + type Error = Error; } - fn write_read<'a>( - &'a mut self, - address: u8, - bytes: &'a [u8], - buffer: &'a mut [u8], - ) -> Self::WriteReadFuture<'a> { - self.write_read(address, bytes, buffer) + impl<'d, T: Instance, TXDMA: TxDma, RXDMA: RxDma> embedded_hal_async::i2c::I2c + for I2c<'d, T, TXDMA, RXDMA> + { + type ReadFuture<'a> + where + Self: 'a, + = impl Future> + 'a; + + fn read<'a>(&'a mut self, address: u8, buffer: &'a mut [u8]) -> Self::ReadFuture<'a> { + self.read(address, buffer) + } + + type WriteFuture<'a> + where + Self: 'a, + = impl Future> + 'a; + fn write<'a>(&'a mut self, address: u8, bytes: &'a [u8]) -> Self::WriteFuture<'a> { + self.write(address, bytes) + } + + type WriteReadFuture<'a> + where + Self: 'a, + = impl Future> + 'a; + fn write_read<'a>( + &'a mut self, + address: u8, + bytes: &'a [u8], + buffer: &'a mut [u8], + ) -> Self::WriteReadFuture<'a> { + self.write_read(address, bytes, buffer) + } + + type TransactionFuture<'a> + where + Self: 'a, + = impl Future> + 'a; + + fn transaction<'a>( + &'a mut self, + address: u8, + operations: &mut [embedded_hal_async::i2c::Operation<'a>], + ) -> Self::TransactionFuture<'a> { + let _ = address; + let _ = operations; + async move { todo!() } + } } } diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs index f1ea8592d..4cf45f6f9 100644 --- a/embassy-stm32/src/spi/mod.rs +++ b/embassy-stm32/src/spi/mod.rs @@ -1,11 +1,9 @@ #![macro_use] -use core::future::Future; use core::marker::PhantomData; use core::ptr; use embassy::util::Unborrow; use embassy_hal_common::unborrow; -use embassy_traits::spi as traits; use self::sealed::WordSize; use crate::dma; @@ -17,7 +15,7 @@ use crate::peripherals; use crate::rcc::RccPeripheral; use crate::time::Hertz; -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}; #[cfg_attr(spi_v1, path = "v1.rs")] #[cfg_attr(spi_f1, path = "v1.rs")] @@ -549,76 +547,168 @@ fn transfer_word(regs: Regs, tx_word: W) -> Result { return Ok(rx_word); } -// Note: It is not possible to impl these traits generically in embedded-hal 0.2 due to a conflict with -// some marker traits. For details, see https://github.com/rust-embedded/embedded-hal/pull/289 -macro_rules! impl_blocking { - ($w:ident) => { - impl<'d, T: Instance> embedded_hal::blocking::spi::Write<$w> for Spi<'d, T, NoDma, NoDma> { - type Error = Error; +mod eh02 { + use super::*; - fn write(&mut self, words: &[$w]) -> Result<(), Self::Error> { - self.blocking_write(words) + // Note: It is not possible to impl these traits generically in embedded-hal 0.2 due to a conflict with + // some marker traits. For details, see https://github.com/rust-embedded/embedded-hal/pull/289 + macro_rules! impl_blocking { + ($w:ident) => { + impl<'d, T: Instance> embedded_hal_02::blocking::spi::Write<$w> + for Spi<'d, T, NoDma, NoDma> + { + type Error = Error; + + fn write(&mut self, words: &[$w]) -> Result<(), Self::Error> { + self.blocking_write(words) + } + } + + impl<'d, T: Instance> embedded_hal_02::blocking::spi::Transfer<$w> + for Spi<'d, T, NoDma, NoDma> + { + type Error = Error; + + fn transfer<'w>(&mut self, words: &'w mut [$w]) -> Result<&'w [$w], Self::Error> { + self.blocking_transfer_in_place(words)?; + Ok(words) + } + } + }; + } + + impl_blocking!(u8); + impl_blocking!(u16); +} + +#[cfg(feature = "unstable-traits")] +mod eh1 { + use super::*; + use core::future::Future; + + impl<'d, T: Instance, Tx, Rx> embedded_hal_1::spi::ErrorType for Spi<'d, T, Tx, Rx> { + type Error = Error; + } + + impl embedded_hal_1::spi::Error for Error { + fn kind(&self) -> embedded_hal_1::spi::ErrorKind { + match *self { + Self::Framing => embedded_hal_1::spi::ErrorKind::FrameFormat, + Self::Crc => embedded_hal_1::spi::ErrorKind::Other, + Self::ModeFault => embedded_hal_1::spi::ErrorKind::ModeFault, + Self::Overrun => embedded_hal_1::spi::ErrorKind::Overrun, } } + } - impl<'d, T: Instance> embedded_hal::blocking::spi::Transfer<$w> - for Spi<'d, T, NoDma, NoDma> - { - type Error = Error; + impl<'d, T: Instance, Tx: TxDmaChannel, Rx> embedded_hal_async::spi::Write + for Spi<'d, T, Tx, Rx> + { + type WriteFuture<'a> + where + Self: 'a, + = impl Future> + 'a; - fn transfer<'w>(&mut self, words: &'w mut [$w]) -> Result<&'w [$w], Self::Error> { - self.blocking_transfer_in_place(words)?; - Ok(words) + fn write<'a>(&'a mut self, data: &'a [u8]) -> Self::WriteFuture<'a> { + self.write(data) + } + + type WriteTransactionFuture<'a> + where + Self: 'a, + = impl Future> + 'a; + + fn write_transaction<'a>( + &'a mut self, + words: &'a [&'a [u8]], + ) -> Self::WriteTransactionFuture<'a> { + async move { + for buf in words { + self.write(buf).await? + } + Ok(()) } } - }; -} - -impl_blocking!(u8); -impl_blocking!(u16); - -impl<'d, T: Instance, Tx, Rx> traits::Spi for Spi<'d, T, Tx, Rx> { - type Error = Error; -} - -impl<'d, T: Instance, Tx: TxDmaChannel, Rx> traits::Write for Spi<'d, T, Tx, Rx> { - type WriteFuture<'a> - where - Self: 'a, - = impl Future> + 'a; - - fn write<'a>(&'a mut self, data: &'a [u8]) -> Self::WriteFuture<'a> { - self.write(data) } -} -impl<'d, T: Instance, Tx: TxDmaChannel, Rx: RxDmaChannel> traits::Read - for Spi<'d, T, Tx, Rx> -{ - type ReadFuture<'a> - where - Self: 'a, - = impl Future> + 'a; + impl<'d, T: Instance, Tx: TxDmaChannel, Rx: RxDmaChannel> + embedded_hal_async::spi::Read for Spi<'d, T, Tx, Rx> + { + type ReadFuture<'a> + where + Self: 'a, + = impl Future> + 'a; - fn read<'a>(&'a mut self, data: &'a mut [u8]) -> Self::ReadFuture<'a> { - self.read(data) + fn read<'a>(&'a mut self, data: &'a mut [u8]) -> Self::ReadFuture<'a> { + self.read(data) + } + + type ReadTransactionFuture<'a> + where + Self: 'a, + = impl Future> + 'a; + + fn read_transaction<'a>( + &'a mut self, + words: &'a mut [&'a mut [u8]], + ) -> Self::ReadTransactionFuture<'a> { + async move { + for buf in words { + self.read(buf).await? + } + Ok(()) + } + } } -} -impl<'d, T: Instance, Tx: TxDmaChannel, Rx: RxDmaChannel> traits::FullDuplex - for Spi<'d, T, Tx, Rx> -{ - type WriteReadFuture<'a> - where - Self: 'a, - = impl Future> + 'a; + impl<'d, T: Instance, Tx: TxDmaChannel, Rx: RxDmaChannel> + embedded_hal_async::spi::ReadWrite for Spi<'d, T, Tx, Rx> + { + type TransferFuture<'a> + where + Self: 'a, + = impl Future> + 'a; - fn read_write<'a>( - &'a mut self, - read: &'a mut [u8], - write: &'a [u8], - ) -> Self::WriteReadFuture<'a> { - self.transfer(read, write) + fn transfer<'a>(&'a mut self, rx: &'a mut [u8], tx: &'a [u8]) -> Self::TransferFuture<'a> { + self.transfer(rx, tx) + } + + type TransferInPlaceFuture<'a> + where + Self: 'a, + = impl Future> + 'a; + + fn transfer_in_place<'a>( + &'a mut self, + words: &'a mut [u8], + ) -> Self::TransferInPlaceFuture<'a> { + // TODO: Implement async version + let result = self.blocking_transfer_in_place(words); + async move { result } + } + + type TransactionFuture<'a> + where + Self: 'a, + = impl Future> + 'a; + + fn transaction<'a>( + &'a mut self, + operations: &'a mut [embedded_hal_async::spi::Operation<'a, u8>], + ) -> Self::TransactionFuture<'a> { + use embedded_hal_1::spi::blocking::Operation; + async move { + for o in operations { + match o { + Operation::Read(b) => self.read(b).await?, + Operation::Write(b) => self.write(b).await?, + Operation::Transfer(r, w) => self.transfer(r, w).await?, + Operation::TransferInPlace(b) => self.transfer_in_place(b).await?, + } + } + Ok(()) + } + } } } diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index 5309c6296..a391379c8 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs @@ -1,11 +1,9 @@ #![macro_use] -use core::future::Future; use core::marker::PhantomData; use embassy::interrupt::Interrupt; use embassy::util::Unborrow; use embassy_hal_common::unborrow; -use futures::TryFutureExt; use crate::dma::NoDma; use crate::gpio::sealed::AFType::{OutputOpenDrain, OutputPushPull}; @@ -211,72 +209,108 @@ impl<'d, T: Instance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { } } -impl<'d, T: Instance, TxDma, RxDma> embedded_hal::serial::Read for Uart<'d, T, TxDma, RxDma> { - type Error = Error; - fn read(&mut self) -> Result> { - let r = self.inner.regs(); - unsafe { - let sr = sr(r).read(); - if sr.pe() { - rdr(r).read_volatile(); - Err(nb::Error::Other(Error::Parity)) - } else if sr.fe() { - rdr(r).read_volatile(); - Err(nb::Error::Other(Error::Framing)) - } else if sr.ne() { - rdr(r).read_volatile(); - Err(nb::Error::Other(Error::Noise)) - } else if sr.ore() { - rdr(r).read_volatile(); - Err(nb::Error::Other(Error::Overrun)) - } else if sr.rxne() { - Ok(rdr(r).read_volatile()) - } else { - Err(nb::Error::WouldBlock) +mod eh02 { + use super::*; + + impl<'d, T: Instance, TxDma, RxDma> embedded_hal_02::serial::Read + for Uart<'d, T, TxDma, RxDma> + { + type Error = Error; + fn read(&mut self) -> Result> { + let r = self.inner.regs(); + unsafe { + let sr = sr(r).read(); + if sr.pe() { + rdr(r).read_volatile(); + Err(nb::Error::Other(Error::Parity)) + } else if sr.fe() { + rdr(r).read_volatile(); + Err(nb::Error::Other(Error::Framing)) + } else if sr.ne() { + rdr(r).read_volatile(); + Err(nb::Error::Other(Error::Noise)) + } else if sr.ore() { + rdr(r).read_volatile(); + Err(nb::Error::Other(Error::Overrun)) + } else if sr.rxne() { + Ok(rdr(r).read_volatile()) + } else { + Err(nb::Error::WouldBlock) + } } } } + + impl<'d, T: Instance, TxDma, RxDma> embedded_hal_02::blocking::serial::Write + for Uart<'d, T, TxDma, RxDma> + { + type Error = Error; + fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> { + self.blocking_write(buffer) + } + fn bflush(&mut self) -> Result<(), Self::Error> { + self.blocking_flush() + } + } } -impl<'d, T: Instance, TxDma, RxDma> embedded_hal::blocking::serial::Write - for Uart<'d, T, TxDma, RxDma> -{ - type Error = Error; - fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> { - self.blocking_write(buffer) - } - fn bflush(&mut self) -> Result<(), Self::Error> { - self.blocking_flush() - } -} +#[cfg(feature = "unstable-traits")] +mod eh1 { + use super::*; + use core::future::Future; -impl<'d, T: Instance, TxDma, RxDma> embassy_traits::uart::Write for Uart<'d, T, TxDma, RxDma> -where - TxDma: crate::usart::TxDma, -{ - type WriteFuture<'a> + impl embedded_hal_1::serial::Error for Error { + fn kind(&self) -> embedded_hal_1::serial::ErrorKind { + match *self { + Self::Framing => embedded_hal_1::serial::ErrorKind::FrameFormat, + Self::Noise => embedded_hal_1::serial::ErrorKind::Noise, + Self::Overrun => embedded_hal_1::serial::ErrorKind::Overrun, + Self::Parity => embedded_hal_1::serial::ErrorKind::Parity, + } + } + } + + impl<'d, T: Instance, TxDma, RxDma> embedded_hal_1::serial::ErrorType + for Uart<'d, T, TxDma, RxDma> + { + type Error = Error; + } + + impl<'d, T: Instance, TxDma, RxDma> embedded_hal_async::serial::Write for Uart<'d, T, TxDma, RxDma> where - Self: 'a, - = impl Future> + 'a; + TxDma: crate::usart::TxDma, + { + type WriteFuture<'a> + where + Self: 'a, + = impl Future> + 'a; - fn write<'a>(&'a mut self, buf: &'a [u8]) -> Self::WriteFuture<'a> { - self.write(buf) - .map_err(|_| embassy_traits::uart::Error::Other) + fn write<'a>(&'a mut self, buf: &'a [u8]) -> Self::WriteFuture<'a> { + self.write(buf) + } + + type FlushFuture<'a> + where + Self: 'a, + = impl Future> + 'a; + + fn flush<'a>(&'a mut self) -> Self::FlushFuture<'a> { + async move { Ok(()) } + } } -} -impl<'d, T: Instance, TxDma, RxDma> embassy_traits::uart::Read for Uart<'d, T, TxDma, RxDma> -where - RxDma: crate::usart::RxDma, -{ - type ReadFuture<'a> + impl<'d, T: Instance, TxDma, RxDma> embedded_hal_async::serial::Read for Uart<'d, T, TxDma, RxDma> where - Self: 'a, - = impl Future> + 'a; + RxDma: crate::usart::RxDma, + { + type ReadFuture<'a> + where + Self: 'a, + = impl Future> + 'a; - fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReadFuture<'a> { - self.read(buf) - .map_err(|_| embassy_traits::uart::Error::Other) + fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReadFuture<'a> { + self.read(buf) + } } } diff --git a/embassy-traits/Cargo.toml b/embassy-traits/Cargo.toml index a93cb3c54..4d0d21916 100644 --- a/embassy-traits/Cargo.toml +++ b/embassy-traits/Cargo.toml @@ -9,5 +9,7 @@ std = [] [dependencies] defmt = { version = "0.3", optional = true } -embedded-hal = { version = "0.2.6", features = ["unproven"] } +embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } +embedded-hal-1 = { package = "embedded-hal", version = "1.0.0-alpha.6", git = "https://github.com/embassy-rs/embedded-hal", branch = "embassy" } +embedded-hal-async = { version = "0.0.1", git = "https://github.com/embassy-rs/embedded-hal", branch = "embassy"} nb = "1.0.0" diff --git a/embassy-traits/src/adapter.rs b/embassy-traits/src/adapter.rs index ce7dd411f..415b5e814 100644 --- a/embassy-traits/src/adapter.rs +++ b/embassy-traits/src/adapter.rs @@ -1,6 +1,6 @@ use core::future::Future; -use embedded_hal::blocking; -use embedded_hal::serial; +use embedded_hal_02::blocking; +use embedded_hal_02::serial; /// BlockingAsync is a wrapper that implements async traits using blocking peripherals. This allows /// driver writers to depend on the async traits while still supporting embedded-hal peripheral implementations. @@ -20,24 +20,37 @@ impl BlockingAsync { } // -// I2C implementatinos +// I2C implementations // - -impl crate::i2c::I2c for BlockingAsync +impl embedded_hal_1::i2c::ErrorType for BlockingAsync where - E: 'static, + E: embedded_hal_1::i2c::Error + 'static, T: blocking::i2c::WriteRead + blocking::i2c::Read + blocking::i2c::Write, { type Error = E; +} - #[rustfmt::skip] - type WriteFuture<'a> where Self: 'a = impl Future> + 'a; - #[rustfmt::skip] - type ReadFuture<'a> where Self: 'a = impl Future> + 'a; - #[rustfmt::skip] - type WriteReadFuture<'a> where Self: 'a = impl Future> + 'a; +impl embedded_hal_async::i2c::I2c for BlockingAsync +where + E: embedded_hal_1::i2c::Error + 'static, + T: blocking::i2c::WriteRead + + blocking::i2c::Read + + blocking::i2c::Write, +{ + type WriteFuture<'a> + where + Self: 'a, + = impl Future> + 'a; + type ReadFuture<'a> + where + Self: 'a, + = impl Future> + 'a; + type WriteReadFuture<'a> + where + Self: 'a, + = impl Future> + 'a; fn read<'a>(&'a mut self, address: u8, buffer: &'a mut [u8]) -> Self::ReadFuture<'a> { async move { self.wrapped.read(address, buffer) } @@ -55,33 +68,46 @@ where ) -> Self::WriteReadFuture<'a> { async move { self.wrapped.write_read(address, bytes, buffer) } } + + type TransactionFuture<'a> + where + Self: 'a, + = impl Future> + 'a; + + fn transaction<'a>( + &'a mut self, + address: u8, + operations: &mut [embedded_hal_async::i2c::Operation<'a>], + ) -> Self::TransactionFuture<'a> { + let _ = address; + let _ = operations; + async move { todo!() } + } } // // SPI implementatinos // -impl crate::spi::Spi for BlockingAsync +impl embedded_hal_async::spi::ErrorType for BlockingAsync where - T: blocking::spi::Write, + E: embedded_hal_1::spi::Error, + T: blocking::spi::Transfer + blocking::spi::Write, { type Error = E; } -impl crate::spi::FullDuplex for BlockingAsync +impl embedded_hal_async::spi::ReadWrite for BlockingAsync where - E: 'static, - Word: Clone, - T: blocking::spi::Transfer + blocking::spi::Write, + E: embedded_hal_1::spi::Error + 'static, + T: blocking::spi::Transfer + blocking::spi::Write, { - #[rustfmt::skip] - type WriteReadFuture<'a> where Word: 'a, Self: 'a = impl Future> + 'a; + type TransferFuture<'a> + where + Self: 'a, + = impl Future> + 'a; - fn read_write<'a>( - &'a mut self, - read: &'a mut [Word], - write: &'a [Word], - ) -> Self::WriteReadFuture<'a> { + fn transfer<'a>(&'a mut self, read: &'a mut [u8], write: &'a [u8]) -> Self::TransferFuture<'a> { async move { // Ensure we write the expected bytes for i in 0..core::cmp::min(read.len(), write.len()) { @@ -91,53 +117,111 @@ where Ok(()) } } -} -impl crate::spi::Write for BlockingAsync -where - E: 'static, - Word: Clone, - T: blocking::spi::Write, -{ - #[rustfmt::skip] - type WriteFuture<'a> where Word: 'a, Self: 'a = impl Future> + 'a; + type TransferInPlaceFuture<'a> + where + Self: 'a, + = impl Future> + 'a; - fn write<'a>(&'a mut self, data: &'a [Word]) -> Self::WriteFuture<'a> { - async move { self.wrapped.write(data) } + fn transfer_in_place<'a>(&'a mut self, _: &'a mut [u8]) -> Self::TransferInPlaceFuture<'a> { + async move { todo!() } + } + + type TransactionFuture<'a> + where + Self: 'a, + = impl Future> + 'a; + + fn transaction<'a>( + &'a mut self, + _: &'a mut [embedded_hal_async::spi::Operation<'a, u8>], + ) -> Self::TransactionFuture<'a> { + async move { todo!() } } } -impl crate::spi::Read for BlockingAsync +impl embedded_hal_async::spi::Write for BlockingAsync where - E: 'static, - Word: Clone, - T: blocking::spi::Transfer + blocking::spi::Write, + E: embedded_hal_1::spi::Error + 'static, + T: blocking::spi::Transfer + blocking::spi::Write, { - #[rustfmt::skip] - type ReadFuture<'a> where Word: 'a, Self: 'a = impl Future> + 'a; + type WriteFuture<'a> + where + Self: 'a, + = impl Future> + 'a; - fn read<'a>(&'a mut self, data: &'a mut [Word]) -> Self::ReadFuture<'a> { + fn write<'a>(&'a mut self, data: &'a [u8]) -> Self::WriteFuture<'a> { + async move { + self.wrapped.write(data)?; + Ok(()) + } + } + + type WriteTransactionFuture<'a> + where + Self: 'a, + = impl Future> + 'a; + + fn write_transaction<'a>(&'a mut self, _: &'a [&'a [u8]]) -> Self::WriteTransactionFuture<'a> { + async move { todo!() } + } +} + +impl embedded_hal_async::spi::Read for BlockingAsync +where + E: embedded_hal_1::spi::Error + 'static, + T: blocking::spi::Transfer + blocking::spi::Write, +{ + type ReadFuture<'a> + where + Self: 'a, + = impl Future> + 'a; + + fn read<'a>(&'a mut self, data: &'a mut [u8]) -> Self::ReadFuture<'a> { async move { self.wrapped.transfer(data)?; Ok(()) } } + + type ReadTransactionFuture<'a> + where + Self: 'a, + = impl Future> + 'a; + + fn read_transaction<'a>( + &'a mut self, + _: &'a mut [&'a mut [u8]], + ) -> Self::ReadTransactionFuture<'a> { + async move { todo!() } + } } // Uart implementatinos -impl crate::uart::Read for BlockingAsync +impl embedded_hal_1::serial::ErrorType for BlockingAsync where - T: serial::Read, + T: serial::Read, + E: embedded_hal_1::serial::Error + 'static, { - #[rustfmt::skip] - type ReadFuture<'a> where T: 'a = impl Future> + 'a; + type Error = E; +} + +impl embedded_hal_async::serial::Read for BlockingAsync +where + T: serial::Read, + E: embedded_hal_1::serial::Error + 'static, +{ + type ReadFuture<'a> + where + T: 'a, + = impl Future> + 'a; fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReadFuture<'a> { async move { let mut pos = 0; while pos < buf.len() { match self.wrapped.read() { Err(nb::Error::WouldBlock) => {} - Err(_) => return Err(crate::uart::Error::Other), + Err(nb::Error::Other(e)) => return Err(e), Ok(b) => { buf[pos] = b; pos += 1; @@ -149,18 +233,24 @@ where } } -impl crate::uart::Write for BlockingAsync +impl embedded_hal_async::serial::Write for BlockingAsync where - T: blocking::serial::Write, + T: blocking::serial::Write + serial::Read, + E: embedded_hal_1::serial::Error + 'static, { - #[rustfmt::skip] - type WriteFuture<'a> where T: 'a = impl Future> + 'a; + type WriteFuture<'a> + where + T: 'a, + = impl Future> + 'a; fn write<'a>(&'a mut self, buf: &'a [u8]) -> Self::WriteFuture<'a> { - async move { - self.wrapped - .bwrite_all(buf) - .map_err(|_| crate::uart::Error::Other)?; - self.wrapped.bflush().map_err(|_| crate::uart::Error::Other) - } + async move { self.wrapped.bwrite_all(buf) } + } + + type FlushFuture<'a> + where + T: 'a, + = impl Future> + 'a; + fn flush<'a>(&'a mut self) -> Self::FlushFuture<'a> { + async move { self.wrapped.bflush() } } } diff --git a/embassy-traits/src/gpio.rs b/embassy-traits/src/gpio.rs deleted file mode 100644 index 3752c8d60..000000000 --- a/embassy-traits/src/gpio.rs +++ /dev/null @@ -1,57 +0,0 @@ -use core::future::Future; - -/// Wait for a pin to become high. -pub trait WaitForHigh { - type Future<'a>: Future + 'a - where - Self: 'a; - - /// Wait for a pin to become high. - /// - /// If the pin is already high, the future completes immediately. - /// Otherwise, it completes when it becomes high. - fn wait_for_high(&mut self) -> Self::Future<'_>; -} - -/// Wait for a pin to become low. -pub trait WaitForLow { - type Future<'a>: Future + 'a - where - Self: 'a; - - /// Wait for a pin to become low. - /// - /// If the pin is already low, the future completes immediately. - /// Otherwise, it completes when it becomes low. - fn wait_for_low(&mut self) -> Self::Future<'_>; -} - -/// Wait for a rising edge (transition from low to high) -pub trait WaitForRisingEdge { - type Future<'a>: Future + 'a - where - Self: 'a; - - /// Wait for a rising edge (transition from low to high) - fn wait_for_rising_edge(&mut self) -> Self::Future<'_>; -} - -/// Wait for a falling edge (transition from high to low) -pub trait WaitForFallingEdge { - type Future<'a>: Future + 'a - where - Self: 'a; - - /// Wait for a falling edge (transition from high to low) - fn wait_for_falling_edge(&'_ mut self) -> Self::Future<'_>; -} - -/// Wait for any edge (any transition, high to low or low to high) -pub trait WaitForAnyEdge { - type Future<'a>: Future + 'a - where - Self: 'a; - - /// Wait for any edge (any transition, high to low or low to high) - fn wait_for_any_edge(&mut self) -> Self::Future<'_>; -} diff --git a/embassy-traits/src/i2c.rs b/embassy-traits/src/i2c.rs deleted file mode 100644 index 4e2e8e2f0..000000000 --- a/embassy-traits/src/i2c.rs +++ /dev/null @@ -1,192 +0,0 @@ -//! Async I2C API -//! -//! This API supports 7-bit and 10-bit addresses. Traits feature an `AddressMode` -//! marker type parameter. Two implementation of the `AddressMode` exist: -//! `SevenBitAddress` and `TenBitAddress`. -//! -//! Through this marker types it is possible to implement each address mode for -//! the traits independently in `embedded-hal` implementations and device drivers -//! can depend only on the mode that they support. -//! -//! Additionally, the I2C 10-bit address mode has been developed to be fully -//! backwards compatible with the 7-bit address mode. This allows for a -//! software-emulated 10-bit addressing implementation if the address mode -//! is not supported by the hardware. -//! -//! Since 7-bit addressing is the mode of the majority of I2C devices, -//! `SevenBitAddress` has been set as default mode and thus can be omitted if desired. -//! -//! ### Device driver compatible only with 7-bit addresses -//! -//! For demonstration purposes the address mode parameter has been omitted in this example. -//! -//! ``` -//! # use embassy_traits::i2c::I2c; -//! const ADDR: u8 = 0x15; -//! # const TEMP_REGISTER: u8 = 0x1; -//! pub struct TemperatureSensorDriver { -//! i2c: I2C, -//! } -//! -//! impl TemperatureSensorDriver -//! where -//! I2C: I2c, -//! { -//! pub fn read_temperature(&mut self) -> Result { -//! let mut temp = [0]; -//! self.i2c -//! .write_read(ADDR, &[TEMP_REGISTER], &mut temp) -//! .await -//! .and(Ok(temp[0])) -//! } -//! } -//! ``` -//! -//! ### Device driver compatible only with 10-bit addresses -//! -//! ``` -//! # use embassy_traits::i2c::{TenBitAddress, I2c}; -//! const ADDR: u16 = 0x158; -//! # const TEMP_REGISTER: u8 = 0x1; -//! pub struct TemperatureSensorDriver { -//! i2c: I2C, -//! } -//! -//! impl TemperatureSensorDriver -//! where -//! I2C: I2c, -//! { -//! pub fn read_temperature(&mut self) -> Result { -//! let mut temp = [0]; -//! self.i2c -//! .write_read(ADDR, &[TEMP_REGISTER], &mut temp) -//! .await -//! .and(Ok(temp[0])) -//! } -//! } -//! ``` - -use core::future::Future; - -mod private { - pub trait Sealed {} -} - -/// Address mode (7-bit / 10-bit) -/// -/// Note: This trait is sealed and should not be implemented outside of this crate. -pub trait AddressMode: private::Sealed {} - -/// 7-bit address mode type -pub type SevenBitAddress = u8; - -/// 10-bit address mode type -pub type TenBitAddress = u16; - -impl private::Sealed for SevenBitAddress {} -impl private::Sealed for TenBitAddress {} - -impl AddressMode for SevenBitAddress {} - -impl AddressMode for TenBitAddress {} - -pub trait I2c { - /// Error type - type Error; - - type WriteFuture<'a>: Future> + 'a - where - Self: 'a; - type ReadFuture<'a>: Future> + 'a - where - Self: 'a; - type WriteReadFuture<'a>: Future> + 'a - where - Self: 'a; - - /// Reads enough bytes from slave with `address` to fill `buffer` - /// - /// # I2C Events (contract) - /// - /// ``` text - /// Master: ST SAD+R MAK MAK ... NMAK SP - /// Slave: SAK B0 B1 ... BN - /// ``` - /// - /// Where - /// - /// - `ST` = start condition - /// - `SAD+R` = slave address followed by bit 1 to indicate reading - /// - `SAK` = slave acknowledge - /// - `Bi` = ith byte of data - /// - `MAK` = master acknowledge - /// - `NMAK` = master no acknowledge - /// - `SP` = stop condition - fn read<'a>(&'a mut self, address: A, buffer: &'a mut [u8]) -> Self::ReadFuture<'a>; - - /// Sends bytes to slave with address `address` - /// - /// # I2C Events (contract) - /// - /// ``` text - /// Master: ST SAD+W B0 B1 ... BN SP - /// Slave: SAK SAK SAK ... SAK - /// ``` - /// - /// Where - /// - /// - `ST` = start condition - /// - `SAD+W` = slave address followed by bit 0 to indicate writing - /// - `SAK` = slave acknowledge - /// - `Bi` = ith byte of data - /// - `SP` = stop condition - fn write<'a>(&'a mut self, address: A, bytes: &'a [u8]) -> Self::WriteFuture<'a>; - - /// Sends bytes to slave with address `address` and then reads enough bytes to fill `buffer` *in a - /// single transaction* - /// - /// # I2C Events (contract) - /// - /// ``` text - /// Master: ST SAD+W O0 O1 ... OM SR SAD+R MAK MAK ... NMAK SP - /// Slave: SAK SAK SAK ... SAK SAK I0 I1 ... IN - /// ``` - /// - /// Where - /// - /// - `ST` = start condition - /// - `SAD+W` = slave address followed by bit 0 to indicate writing - /// - `SAK` = slave acknowledge - /// - `Oi` = ith outgoing byte of data - /// - `SR` = repeated start condition - /// - `SAD+R` = slave address followed by bit 1 to indicate reading - /// - `Ii` = ith incoming byte of data - /// - `MAK` = master acknowledge - /// - `NMAK` = master no acknowledge - /// - `SP` = stop condition - fn write_read<'a>( - &'a mut self, - address: A, - bytes: &'a [u8], - buffer: &'a mut [u8], - ) -> Self::WriteReadFuture<'a>; -} - -pub trait WriteIter { - /// Error type - type Error; - - type WriteIterFuture<'a, V>: Future> + 'a - where - V: 'a + IntoIterator, - Self: 'a; - - /// Sends bytes to slave with address `address` - /// - /// # I2C Events (contract) - /// - /// Same as `I2c::write` - fn write_iter<'a, U>(&'a mut self, address: A, bytes: U) -> Self::WriteIterFuture<'a, U> - where - U: IntoIterator + 'a; -} diff --git a/embassy-traits/src/lib.rs b/embassy-traits/src/lib.rs index a5342b77e..a41d0106f 100644 --- a/embassy-traits/src/lib.rs +++ b/embassy-traits/src/lib.rs @@ -5,8 +5,4 @@ pub mod adapter; pub mod delay; pub mod flash; -pub mod gpio; -pub mod i2c; pub mod rng; -pub mod spi; -pub mod uart; diff --git a/embassy-traits/src/spi.rs b/embassy-traits/src/spi.rs deleted file mode 100644 index 6beb442ba..000000000 --- a/embassy-traits/src/spi.rs +++ /dev/null @@ -1,61 +0,0 @@ -//! Async SPI API - -use core::future::Future; - -/// Full duplex (master mode) -/// -/// # Notes -/// -/// - It's the task of the user of this interface to manage the slave select lines -/// -/// - Due to how full duplex SPI works each `read` call must be preceded by a `write` call. -/// -/// - `read` calls only return the data received with the last `write` call. -/// Previously received data is discarded -/// -/// - Data is only guaranteed to be clocked out when the `read` call succeeds. -/// The slave select line shouldn't be released before that. -/// -/// - Some SPIs can work with 8-bit *and* 16-bit words. You can overload this trait with different -/// `Word` types to allow operation in both modes. - -pub trait Spi { - /// An enumeration of SPI errors - type Error; -} - -pub trait FullDuplex: Spi + Write + Read { - type WriteReadFuture<'a>: Future> + 'a - where - Self: 'a, - Word: 'a; - - /// The `read` array must be at least as long as the `write` array, - /// but is guaranteed to only be filled with bytes equal to the - /// length of the `write` array. - fn read_write<'a>( - &'a mut self, - read: &'a mut [Word], - write: &'a [Word], - ) -> Self::WriteReadFuture<'a>; -} - -pub trait Write: Spi { - type WriteFuture<'a>: Future> + 'a - where - Self: 'a, - Word: 'a; - - /// Writes `data` to the peripheral, ignoring all the incoming words. - fn write<'a>(&'a mut self, data: &'a [Word]) -> Self::WriteFuture<'a>; -} - -pub trait Read: Write { - type ReadFuture<'a>: Future> + 'a - where - Self: 'a, - Word: 'a; - - /// Reads words into `data` from the peripheral. - fn read<'a>(&'a mut self, data: &'a mut [Word]) -> Self::ReadFuture<'a>; -} diff --git a/embassy-traits/src/uart.rs b/embassy-traits/src/uart.rs deleted file mode 100644 index 4984bc89c..000000000 --- a/embassy-traits/src/uart.rs +++ /dev/null @@ -1,36 +0,0 @@ -use core::future::Future; - -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -#[non_exhaustive] -pub enum Error { - Other, -} - -pub trait Read { - type ReadFuture<'a>: Future> - where - Self: 'a; - - /// Receive into the buffer until the buffer is full. - fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReadFuture<'a>; -} - -pub trait ReadUntilIdle { - type ReadUntilIdleFuture<'a>: Future> - where - Self: 'a; - - /// Receive into the buffer until the buffer is full or the line is idle after some bytes are received - /// Return the number of bytes received - fn read_until_idle<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReadUntilIdleFuture<'a>; -} - -pub trait Write { - type WriteFuture<'a>: Future> - where - Self: 'a; - - /// Write all bytes in `buf`. - fn write<'a>(&'a mut self, buf: &'a [u8]) -> Self::WriteFuture<'a>; -} diff --git a/examples/stm32f3/src/bin/spi_dma.rs b/examples/stm32f3/src/bin/spi_dma.rs index a87a36f73..bd66b1202 100644 --- a/examples/stm32f3/src/bin/spi_dma.rs +++ b/examples/stm32f3/src/bin/spi_dma.rs @@ -10,7 +10,6 @@ use embassy::executor::Spawner; use embassy_stm32::spi::{Config, Spi}; use embassy_stm32::time::Hertz; use embassy_stm32::Peripherals; -use embassy_traits::spi::FullDuplex; use example_common::*; use heapless::String; @@ -33,7 +32,7 @@ async fn main(_spawner: Spawner, p: Peripherals) { let mut write: String<128> = String::new(); let mut read = [0; 128]; core::write!(&mut write, "Hello DMA World {}!\r\n", n).unwrap(); - spi.read_write(&mut read[0..write.len()], write.as_bytes()) + spi.transfer(&mut read[0..write.len()], write.as_bytes()) .await .ok(); info!("read via spi+dma: {}", from_utf8(&read).unwrap()); diff --git a/examples/stm32h7/Cargo.toml b/examples/stm32h7/Cargo.toml index 67f1cfc94..16adcdb91 100644 --- a/examples/stm32h7/Cargo.toml +++ b/examples/stm32h7/Cargo.toml @@ -10,7 +10,7 @@ resolver = "2" [dependencies] embassy = { version = "0.1.0", path = "../../embassy", features = ["defmt"] } embassy-traits = { version = "0.1.0", path = "../../embassy-traits", features = ["defmt"] } -embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h743zi", "net", "time-driver-any", "exti", "unstable-pac"] } +embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h743zi", "net", "time-driver-any", "exti", "unstable-pac", "unstable-traits"] } embassy-net = { path = "../../embassy-net", default-features = false, features = ["defmt", "tcp", "medium-ethernet", "pool-16"] } embassy-hal-common = { path = "../../embassy-hal-common", default-features = false, features = ["defmt"] } @@ -20,6 +20,7 @@ defmt-rtt = "0.3" cortex-m = "0.7.3" cortex-m-rt = "0.7.0" embedded-hal = "0.2.6" +embedded-hal-async = { version = "0.0.1", git = "https://github.com/embassy-rs/embedded-hal", branch = "embassy"} panic-probe = { version = "0.3", features = ["print-defmt"] } futures = { version = "0.3.17", default-features = false, features = ["async-await"] } heapless = { version = "0.7.5", default-features = false } diff --git a/examples/stm32h7/src/bin/camera.rs b/examples/stm32h7/src/bin/camera.rs index 9e8071bb3..9760d0f74 100644 --- a/examples/stm32h7/src/bin/camera.rs +++ b/examples/stm32h7/src/bin/camera.rs @@ -128,7 +128,7 @@ mod ov7725 { use defmt::Format; use embassy::time::{Duration, Timer}; use embassy_stm32::rcc::{Mco, McoInstance}; - use embassy_traits::i2c::I2c; + use embedded_hal_async::i2c::I2c; #[repr(u8)] pub enum RgbFormat { diff --git a/examples/stm32h7/src/bin/spi_dma.rs b/examples/stm32h7/src/bin/spi_dma.rs index 192e2e864..15ae09973 100644 --- a/examples/stm32h7/src/bin/spi_dma.rs +++ b/examples/stm32h7/src/bin/spi_dma.rs @@ -9,7 +9,6 @@ use core::fmt::Write; use embassy::executor::Executor; use embassy::util::Forever; use embassy_stm32::time::U32Ext; -use embassy_traits::spi::FullDuplex; use example_common::*; use core::str::from_utf8; @@ -24,8 +23,8 @@ async fn main_task(mut spi: spi::Spi<'static, SPI3, DMA1_CH3, DMA1_CH4>) { let mut write: String<128> = String::new(); let mut read = [0; 128]; core::write!(&mut write, "Hello DMA World {}!\r\n", n).unwrap(); - // read_write will slice the &mut read down to &write's actual length. - spi.read_write(&mut read, write.as_bytes()).await.ok(); + // transfer will slice the &mut read down to &write's actual length. + spi.transfer(&mut read, write.as_bytes()).await.ok(); info!("read via spi+dma: {}", from_utf8(&read).unwrap()); } } diff --git a/examples/stm32l0/Cargo.toml b/examples/stm32l0/Cargo.toml index f101c15f5..2c27e276c 100644 --- a/examples/stm32l0/Cargo.toml +++ b/examples/stm32l0/Cargo.toml @@ -8,7 +8,7 @@ resolver = "2" [dependencies] embassy = { version = "0.1.0", path = "../../embassy", features = ["defmt"] } embassy-traits = { version = "0.1.0", path = "../../embassy-traits", features = ["defmt"] } -embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32l072cz", "time-driver-any", "exti", "memory-x"] } +embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32l072cz", "time-driver-any", "exti", "unstable-traits", "memory-x"] } embassy-lora = { version = "0.1.0", path = "../../embassy-lora", features = ["sx127x", "time", "defmt"] } diff --git a/examples/stm32l4/Cargo.toml b/examples/stm32l4/Cargo.toml index d01c76f6e..ca76a1299 100644 --- a/examples/stm32l4/Cargo.toml +++ b/examples/stm32l4/Cargo.toml @@ -10,7 +10,7 @@ resolver = "2" [dependencies] embassy = { version = "0.1.0", path = "../../embassy", features = ["defmt" ] } embassy-traits = { version = "0.1.0", path = "../../embassy-traits", features = ["defmt"] } -embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "unstable-pac", "stm32l4s5vi", "time-driver-any", "exti"] } +embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "unstable-pac", "stm32l4s5vi", "time-driver-any", "exti", "unstable-traits"] } defmt = "0.3" defmt-rtt = "0.3" @@ -18,6 +18,7 @@ defmt-rtt = "0.3" cortex-m = "0.7.3" cortex-m-rt = "0.7.0" embedded-hal = "0.2.6" +embedded-hal-async = { version = "0.0.1", git = "https://github.com/embassy-rs/embedded-hal", branch = "embassy"} panic-probe = { version = "0.3", features = ["print-defmt"] } futures = { version = "0.3.17", default-features = false, features = ["async-await"] } heapless = { version = "0.7.5", default-features = false } diff --git a/examples/stm32l4/src/bin/i2c_blocking_async.rs b/examples/stm32l4/src/bin/i2c_blocking_async.rs index 0339ed4d3..07077f9fb 100644 --- a/examples/stm32l4/src/bin/i2c_blocking_async.rs +++ b/examples/stm32l4/src/bin/i2c_blocking_async.rs @@ -11,7 +11,8 @@ use embassy_stm32::i2c::I2c; use embassy_stm32::interrupt; use embassy_stm32::time::Hertz; use embassy_stm32::Peripherals; -use embassy_traits::{adapter::BlockingAsync, i2c::I2c as _}; +use embassy_traits::adapter::BlockingAsync; +use embedded_hal_async::i2c::I2c as I2cTrait; use example_common::{info, unwrap}; const ADDRESS: u8 = 0x5F; diff --git a/examples/stm32l4/src/bin/spi_blocking_async.rs b/examples/stm32l4/src/bin/spi_blocking_async.rs index 3be3f21c9..bcd2e32d5 100644 --- a/examples/stm32l4/src/bin/spi_blocking_async.rs +++ b/examples/stm32l4/src/bin/spi_blocking_async.rs @@ -11,7 +11,8 @@ use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed}; use embassy_stm32::spi::{Config, Spi}; use embassy_stm32::time::Hertz; use embassy_stm32::Peripherals; -use embassy_traits::{adapter::BlockingAsync, spi::FullDuplex}; +use embassy_traits::adapter::BlockingAsync; +use embedded_hal_async::spi::ReadWrite; use example_common::*; #[embassy::main] @@ -47,10 +48,10 @@ async fn main(_spawner: Spawner, p: Peripherals) { info!("waiting for ready"); } - let write = [0x0A; 10]; - let mut read = [0; 10]; + let write: [u8; 10] = [0x0A; 10]; + let mut read: [u8; 10] = [0; 10]; cs.set_low(); - spi.read_write(&mut read, &write).await.ok(); + spi.transfer(&mut read, &write).await.ok(); cs.set_high(); info!("xfer {=[u8]:x}", read); } diff --git a/examples/stm32l4/src/bin/spi_dma.rs b/examples/stm32l4/src/bin/spi_dma.rs index d6464bbfa..b4d5091b2 100644 --- a/examples/stm32l4/src/bin/spi_dma.rs +++ b/examples/stm32l4/src/bin/spi_dma.rs @@ -10,7 +10,6 @@ use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed}; use embassy_stm32::spi::{Config, Spi}; use embassy_stm32::time::Hertz; use embassy_stm32::Peripherals; -use embassy_traits::spi::FullDuplex; use example_common::*; #[embassy::main] @@ -47,7 +46,7 @@ async fn main(_spawner: Spawner, p: Peripherals) { let write = [0x0A; 10]; let mut read = [0; 10]; cs.set_low(); - spi.read_write(&mut read, &write).await.ok(); + spi.transfer(&mut read, &write).await.ok(); cs.set_high(); info!("xfer {=[u8]:x}", read); } diff --git a/examples/stm32l4/src/bin/usart_blocking_async.rs b/examples/stm32l4/src/bin/usart_blocking_async.rs index 679d4e0da..10b7127da 100644 --- a/examples/stm32l4/src/bin/usart_blocking_async.rs +++ b/examples/stm32l4/src/bin/usart_blocking_async.rs @@ -6,13 +6,11 @@ mod example_common; use embassy::executor::Spawner; -use embassy::traits::{ - adapter::BlockingAsync, - uart::{Read, Write}, -}; +use embassy::traits::adapter::BlockingAsync; use embassy_stm32::dma::NoDma; use embassy_stm32::usart::{Config, Uart}; use embassy_stm32::Peripherals; +use embedded_hal_async::serial::{Read, Write}; use example_common::*; #[embassy::main] diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml index dc66d08c0..63bfb9d22 100644 --- a/tests/stm32/Cargo.toml +++ b/tests/stm32/Cargo.toml @@ -23,6 +23,7 @@ defmt-rtt = "0.3.0" cortex-m = "0.7.3" cortex-m-rt = "0.7.0" embedded-hal = "0.2.6" +embedded-hal-async = { version = "0.0.1", git = "https://github.com/embassy-rs/embedded-hal", branch = "embassy"} panic-probe = { version = "0.3.0", features = ["print-defmt"] } [profile.dev] diff --git a/tests/stm32/src/bin/spi_dma.rs b/tests/stm32/src/bin/spi_dma.rs index 1a827b434..bf682e097 100644 --- a/tests/stm32/src/bin/spi_dma.rs +++ b/tests/stm32/src/bin/spi_dma.rs @@ -9,7 +9,6 @@ use embassy::executor::Spawner; use embassy_stm32::spi::{self, Spi}; use embassy_stm32::time::Hertz; use embassy_stm32::Peripherals; -use embassy_traits::spi::FullDuplex; use example_common::*; #[embassy::main(config = "config()")] @@ -43,7 +42,7 @@ async fn main(_spawner: Spawner, p: Peripherals) { // Arduino pins D11 and D12 (MOSI-MISO) are connected together with a 1K resistor. // so we should get the data we sent back. let mut buf = [0; 9]; - spi.read_write(&mut buf, &data).await.unwrap(); + spi.transfer(&mut buf, &data).await.unwrap(); assert_eq!(buf, data); info!("Test OK"); From c8347fafb0814078466d7ed220224b9f4c7d78cf Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Wed, 26 Jan 2022 22:49:45 +0100 Subject: [PATCH 2/2] Add unstable-traits for stm32 to CI --- ci.sh | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/ci.sh b/ci.sh index 4b8e77379..452130be2 100755 --- a/ci.sh +++ b/ci.sh @@ -43,18 +43,31 @@ cargo batch \ --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52840,log,gpiote,time-driver-rtc1 \ --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52840,defmt,gpiote,time-driver-rtc1,unstable-traits \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f411ce,defmt,time-driver-any \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f411ce,defmt,time-driver-any,unstable-traits \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f429zi,log,time-driver-any \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f429zi,log,time-driver-any,unstable-traits \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h755zi-cm7,defmt,time-driver-any \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h755zi-cm7,defmt,time-driver-any,unstable-traits \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l476vg,defmt,time-driver-any \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l476vg,defmt,time-driver-any,unstable-traits \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32l072cz,defmt,time-driver-any \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32l072cz,defmt,time-driver-any,unstable-traits \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32l151cb-a,defmt,time-driver-any \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32l151cb-a,defmt,time-driver-any,unstable-traits \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f410tb,defmt,exti,time-driver-any \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f410tb,defmt,exti,time-driver-any,unstable-traits \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f411ce,defmt,exti,time-driver-any \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f411ce,defmt,exti,time-driver-any,unstable-traits \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f429zi,log,exti,time-driver-any \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f429zi,log,exti,time-driver-any,unstable-traits \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h755zi-cm7,defmt,exti,time-driver-any \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h755zi-cm7,defmt,exti,time-driver-any,unstable-traits \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l476vg,defmt,exti,time-driver-any \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l476vg,defmt,exti,time-driver-any,unstable-traits \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32l072cz,defmt,exti,time-driver-any \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32l072cz,defmt,exti,time-driver-any,unstable-traits \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32l151cb-a,defmt,exti,time-driver-any \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32l151cb-a,defmt,exti,time-driver-any,unstable-traits \ --- build --release --manifest-path docs/modules/ROOT/examples/basic/Cargo.toml --target thumbv7em-none-eabi \ --- build --release --manifest-path examples/std/Cargo.toml --target x86_64-unknown-linux-gnu --out-dir out/examples/std \ --- build --release --manifest-path examples/nrf/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/nrf \