Support unstable-trait feature for stm32

This commit is contained in:
Ulf Lilleengen
2022-01-26 22:39:06 +01:00
parent cd36e3f733
commit 4032fc0655
32 changed files with 604 additions and 673 deletions

View File

@ -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"

View File

@ -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<T> BlockingAsync<T> {
}
//
// I2C implementatinos
// I2C implementations
//
impl<T, E> crate::i2c::I2c for BlockingAsync<T>
impl<T, E> embedded_hal_1::i2c::ErrorType for BlockingAsync<T>
where
E: 'static,
E: embedded_hal_1::i2c::Error + 'static,
T: blocking::i2c::WriteRead<Error = E>
+ blocking::i2c::Read<Error = E>
+ blocking::i2c::Write<Error = E>,
{
type Error = E;
}
#[rustfmt::skip]
type WriteFuture<'a> where Self: 'a = impl Future<Output = Result<(), Self::Error>> + 'a;
#[rustfmt::skip]
type ReadFuture<'a> where Self: 'a = impl Future<Output = Result<(), Self::Error>> + 'a;
#[rustfmt::skip]
type WriteReadFuture<'a> where Self: 'a = impl Future<Output = Result<(), Self::Error>> + 'a;
impl<T, E> embedded_hal_async::i2c::I2c for BlockingAsync<T>
where
E: embedded_hal_1::i2c::Error + 'static,
T: blocking::i2c::WriteRead<Error = E>
+ blocking::i2c::Read<Error = E>
+ blocking::i2c::Write<Error = E>,
{
type WriteFuture<'a>
where
Self: 'a,
= impl Future<Output = Result<(), Self::Error>> + 'a;
type ReadFuture<'a>
where
Self: 'a,
= impl Future<Output = Result<(), Self::Error>> + 'a;
type WriteReadFuture<'a>
where
Self: 'a,
= impl Future<Output = Result<(), Self::Error>> + '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<Output = Result<(), Self::Error>> + '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<T, E, Word> crate::spi::Spi<Word> for BlockingAsync<T>
impl<T, E> embedded_hal_async::spi::ErrorType for BlockingAsync<T>
where
T: blocking::spi::Write<Word, Error = E>,
E: embedded_hal_1::spi::Error,
T: blocking::spi::Transfer<u8, Error = E> + blocking::spi::Write<u8, Error = E>,
{
type Error = E;
}
impl<T, E, Word> crate::spi::FullDuplex<Word> for BlockingAsync<T>
impl<T, E> embedded_hal_async::spi::ReadWrite<u8> for BlockingAsync<T>
where
E: 'static,
Word: Clone,
T: blocking::spi::Transfer<Word, Error = E> + blocking::spi::Write<Word, Error = E>,
E: embedded_hal_1::spi::Error + 'static,
T: blocking::spi::Transfer<u8, Error = E> + blocking::spi::Write<u8, Error = E>,
{
#[rustfmt::skip]
type WriteReadFuture<'a> where Word: 'a, Self: 'a = impl Future<Output = Result<(), Self::Error>> + 'a;
type TransferFuture<'a>
where
Self: 'a,
= impl Future<Output = Result<(), Self::Error>> + '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<T, E, Word> crate::spi::Write<Word> for BlockingAsync<T>
where
E: 'static,
Word: Clone,
T: blocking::spi::Write<Word, Error = E>,
{
#[rustfmt::skip]
type WriteFuture<'a> where Word: 'a, Self: 'a = impl Future<Output = Result<(), Self::Error>> + 'a;
type TransferInPlaceFuture<'a>
where
Self: 'a,
= impl Future<Output = Result<(), Self::Error>> + '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<Output = Result<(), Self::Error>> + 'a;
fn transaction<'a>(
&'a mut self,
_: &'a mut [embedded_hal_async::spi::Operation<'a, u8>],
) -> Self::TransactionFuture<'a> {
async move { todo!() }
}
}
impl<T, E, Word> crate::spi::Read<Word> for BlockingAsync<T>
impl<T, E> embedded_hal_async::spi::Write<u8> for BlockingAsync<T>
where
E: 'static,
Word: Clone,
T: blocking::spi::Transfer<Word, Error = E> + blocking::spi::Write<Word, Error = E>,
E: embedded_hal_1::spi::Error + 'static,
T: blocking::spi::Transfer<u8, Error = E> + blocking::spi::Write<u8, Error = E>,
{
#[rustfmt::skip]
type ReadFuture<'a> where Word: 'a, Self: 'a = impl Future<Output = Result<(), Self::Error>> + 'a;
type WriteFuture<'a>
where
Self: 'a,
= impl Future<Output = Result<(), Self::Error>> + '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<Output = Result<(), Self::Error>> + 'a;
fn write_transaction<'a>(&'a mut self, _: &'a [&'a [u8]]) -> Self::WriteTransactionFuture<'a> {
async move { todo!() }
}
}
impl<T, E> embedded_hal_async::spi::Read<u8> for BlockingAsync<T>
where
E: embedded_hal_1::spi::Error + 'static,
T: blocking::spi::Transfer<u8, Error = E> + blocking::spi::Write<u8, Error = E>,
{
type ReadFuture<'a>
where
Self: 'a,
= impl Future<Output = Result<(), Self::Error>> + '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<Output = Result<(), Self::Error>> + 'a;
fn read_transaction<'a>(
&'a mut self,
_: &'a mut [&'a mut [u8]],
) -> Self::ReadTransactionFuture<'a> {
async move { todo!() }
}
}
// Uart implementatinos
impl<T> crate::uart::Read for BlockingAsync<T>
impl<T, E> embedded_hal_1::serial::ErrorType for BlockingAsync<T>
where
T: serial::Read<u8>,
T: serial::Read<u8, Error = E>,
E: embedded_hal_1::serial::Error + 'static,
{
#[rustfmt::skip]
type ReadFuture<'a> where T: 'a = impl Future<Output = Result<(), crate::uart::Error>> + 'a;
type Error = E;
}
impl<T, E> embedded_hal_async::serial::Read for BlockingAsync<T>
where
T: serial::Read<u8, Error = E>,
E: embedded_hal_1::serial::Error + 'static,
{
type ReadFuture<'a>
where
T: 'a,
= impl Future<Output = Result<(), Self::Error>> + '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<T> crate::uart::Write for BlockingAsync<T>
impl<T, E> embedded_hal_async::serial::Write for BlockingAsync<T>
where
T: blocking::serial::Write<u8>,
T: blocking::serial::Write<u8, Error = E> + serial::Read<u8, Error = E>,
E: embedded_hal_1::serial::Error + 'static,
{
#[rustfmt::skip]
type WriteFuture<'a> where T: 'a = impl Future<Output = Result<(), crate::uart::Error>> + 'a;
type WriteFuture<'a>
where
T: 'a,
= impl Future<Output = Result<(), Self::Error>> + '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<Output = Result<(), Self::Error>> + 'a;
fn flush<'a>(&'a mut self) -> Self::FlushFuture<'a> {
async move { self.wrapped.bflush() }
}
}

View File

@ -1,57 +0,0 @@
use core::future::Future;
/// Wait for a pin to become high.
pub trait WaitForHigh {
type Future<'a>: Future<Output = ()> + '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<Output = ()> + '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<Output = ()> + '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<Output = ()> + '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<Output = ()> + '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<'_>;
}

View File

@ -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: I2C,
//! }
//!
//! impl<I2C, E> TemperatureSensorDriver<I2C>
//! where
//! I2C: I2c<Error = E>,
//! {
//! pub fn read_temperature(&mut self) -> Result<u8, E> {
//! 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: I2C,
//! }
//!
//! impl<I2C, E> TemperatureSensorDriver<I2C>
//! where
//! I2C: I2c<TenBitAddress, Error = E>,
//! {
//! pub fn read_temperature(&mut self) -> Result<u8, E> {
//! 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<A: AddressMode = SevenBitAddress> {
/// Error type
type Error;
type WriteFuture<'a>: Future<Output = Result<(), Self::Error>> + 'a
where
Self: 'a;
type ReadFuture<'a>: Future<Output = Result<(), Self::Error>> + 'a
where
Self: 'a;
type WriteReadFuture<'a>: Future<Output = Result<(), Self::Error>> + '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<A: AddressMode = SevenBitAddress> {
/// Error type
type Error;
type WriteIterFuture<'a, V>: Future<Output = Result<(), Self::Error>> + 'a
where
V: 'a + IntoIterator<Item = u8>,
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<Item = u8> + 'a;
}

View File

@ -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;

View File

@ -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<Word> {
/// An enumeration of SPI errors
type Error;
}
pub trait FullDuplex<Word>: Spi<Word> + Write<Word> + Read<Word> {
type WriteReadFuture<'a>: Future<Output = Result<(), Self::Error>> + '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<Word>: Spi<Word> {
type WriteFuture<'a>: Future<Output = Result<(), Self::Error>> + '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<Word>: Write<Word> {
type ReadFuture<'a>: Future<Output = Result<(), Self::Error>> + '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>;
}

View File

@ -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<Output = Result<(), Error>>
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<Output = Result<usize, Error>>
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<Output = Result<(), Error>>
where
Self: 'a;
/// Write all bytes in `buf`.
fn write<'a>(&'a mut self, buf: &'a [u8]) -> Self::WriteFuture<'a>;
}