From f8110e6f028541f38dd94c617c851eb950dd9c63 Mon Sep 17 00:00:00 2001
From: Dario Nieuwenhuis <dirbaio@dirbaio.net>
Date: Sun, 19 Dec 2021 09:19:27 +0100
Subject: [PATCH 1/8] spi: enforce all traits (nb+blocking) have the same Error
 type.

---
 src/spi/blocking.rs | 44 ++++++++------------------------------------
 src/spi/mod.rs      | 12 ++++++++++++
 src/spi/nb.rs       |  9 +++------
 3 files changed, 23 insertions(+), 42 deletions(-)

diff --git a/src/spi/blocking.rs b/src/spi/blocking.rs
index cde2baae9..b2e9b9ee9 100644
--- a/src/spi/blocking.rs
+++ b/src/spi/blocking.rs
@@ -1,10 +1,9 @@
 //! Blocking SPI API
 
-/// Blocking transfer with separate buffers
-pub trait Transfer<W = u8> {
-    /// Error type
-    type Error: crate::spi::Error;
+use super::ErrorType;
 
+/// Blocking transfer with separate buffers
+pub trait Transfer<W = u8>: ErrorType {
     /// Writes and reads simultaneously. `write` is written to the slave on MOSI and
     /// words received on MISO are stored in `read`.
     ///
@@ -17,18 +16,13 @@ pub trait Transfer<W = u8> {
 }
 
 impl<T: Transfer<W>, W> Transfer<W> for &mut T {
-    type Error = T::Error;
-
     fn transfer(&mut self, read: &mut [W], write: &[W]) -> Result<(), Self::Error> {
         T::transfer(self, read, write)
     }
 }
 
 /// Blocking transfer with single buffer (in-place)
-pub trait TransferInplace<W = u8> {
-    /// Error type
-    type Error: crate::spi::Error;
-
+pub trait TransferInplace<W = u8>: ErrorType {
     /// Writes and reads simultaneously. The contents of `words` are
     /// written to the slave, and the received words are stored into the same
     /// `words` buffer, overwriting it.
@@ -36,18 +30,13 @@ pub trait TransferInplace<W = u8> {
 }
 
 impl<T: TransferInplace<W>, W> TransferInplace<W> for &mut T {
-    type Error = T::Error;
-
     fn transfer_inplace(&mut self, words: &mut [W]) -> Result<(), Self::Error> {
         T::transfer_inplace(self, words)
     }
 }
 
 /// Blocking read
-pub trait Read<W = u8> {
-    /// Error type
-    type Error: crate::spi::Error;
-
+pub trait Read<W = u8>: ErrorType {
     /// Reads `words` from the slave.
     ///
     /// The word value sent on MOSI during reading is implementation-defined,
@@ -56,35 +45,25 @@ pub trait Read<W = u8> {
 }
 
 impl<T: Read<W>, W> Read<W> for &mut T {
-    type Error = T::Error;
-
     fn read(&mut self, words: &mut [W]) -> Result<(), Self::Error> {
         T::read(self, words)
     }
 }
 
 /// Blocking write
-pub trait Write<W = u8> {
-    /// Error type
-    type Error: crate::spi::Error;
-
+pub trait Write<W = u8>: ErrorType {
     /// Writes `words` to the slave, ignoring all the incoming words
     fn write(&mut self, words: &[W]) -> Result<(), Self::Error>;
 }
 
 impl<T: Write<W>, W> Write<W> for &mut T {
-    type Error = T::Error;
-
     fn write(&mut self, words: &[W]) -> Result<(), Self::Error> {
         T::write(self, words)
     }
 }
 
 /// Blocking write (iterator version)
-pub trait WriteIter<W = u8> {
-    /// Error type
-    type Error: crate::spi::Error;
-
+pub trait WriteIter<W = u8>: ErrorType {
     /// Writes `words` to the slave, ignoring all the incoming words
     fn write_iter<WI>(&mut self, words: WI) -> Result<(), Self::Error>
     where
@@ -92,8 +71,6 @@ pub trait WriteIter<W = u8> {
 }
 
 impl<T: WriteIter<W>, W> WriteIter<W> for &mut T {
-    type Error = T::Error;
-
     fn write_iter<WI>(&mut self, words: WI) -> Result<(), Self::Error>
     where
         WI: IntoIterator<Item = W>,
@@ -119,17 +96,12 @@ pub enum Operation<'a, W: 'static = u8> {
 
 /// Transactional trait allows multiple actions to be executed
 /// as part of a single SPI transaction
-pub trait Transactional<W: 'static = u8> {
-    /// Associated error type
-    type Error: crate::spi::Error;
-
+pub trait Transactional<W: 'static = u8>: ErrorType {
     /// Execute the provided transactions
     fn exec<'a>(&mut self, operations: &mut [Operation<'a, W>]) -> Result<(), Self::Error>;
 }
 
 impl<T: Transactional<W>, W: 'static> Transactional<W> for &mut T {
-    type Error = T::Error;
-
     fn exec<'a>(&mut self, operations: &mut [Operation<'a, W>]) -> Result<(), Self::Error> {
         T::exec(self, operations)
     }
diff --git a/src/spi/mod.rs b/src/spi/mod.rs
index 048de49a4..a1924251c 100644
--- a/src/spi/mod.rs
+++ b/src/spi/mod.rs
@@ -113,3 +113,15 @@ impl core::fmt::Display for ErrorKind {
         }
     }
 }
+
+/// SPI error type trait
+///
+/// This just defines the error type, to be used by the other SPI traits.
+pub trait ErrorType {
+    /// Error type
+    type Error: Error;
+}
+
+impl<T: ErrorType> ErrorType for &mut T {
+    type Error = T::Error;
+}
diff --git a/src/spi/nb.rs b/src/spi/nb.rs
index 6d540a762..2b9bbe5db 100644
--- a/src/spi/nb.rs
+++ b/src/spi/nb.rs
@@ -1,5 +1,7 @@
 //! Serial Peripheral Interface
 
+use super::ErrorType;
+
 /// Full duplex (master mode)
 ///
 /// # Notes
@@ -16,10 +18,7 @@
 ///
 /// - 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 FullDuplex<Word = u8> {
-    /// An enumeration of SPI errors
-    type Error: crate::spi::Error;
-
+pub trait FullDuplex<Word = u8>: ErrorType {
     /// Reads the word stored in the shift register
     ///
     /// **NOTE** A word must be sent to the slave before attempting to call this
@@ -31,8 +30,6 @@ pub trait FullDuplex<Word = u8> {
 }
 
 impl<T: FullDuplex<Word>, Word> FullDuplex<Word> for &mut T {
-    type Error = T::Error;
-
     fn read(&mut self) -> nb::Result<Word, Self::Error> {
         T::read(self)
     }

From 2c40bbf01e173b57aca5caf750fb1d980e4b61aa Mon Sep 17 00:00:00 2001
From: Dario Nieuwenhuis <dirbaio@dirbaio.net>
Date: Sun, 19 Dec 2021 09:36:35 +0100
Subject: [PATCH 2/8] Add changelog.

---
 CHANGELOG.md | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index ad4fb44ed..078bd683b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -10,6 +10,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
 ### Added
 - `Error` traits for Can, SPI, I2C and Serial are implemented for Infallible
 
+### Changed
+- `spi`: traits now enforce all impls on the same struct (eg `Transfer` and `Write`) have the same `Error` type. 
+
 ## [v1.0.0-alpha.6] - 2021-11-19
 
 *** This is (also) an alpha release with breaking changes (sorry) ***

From 44e0da192232e59648a043aacb54505bd133de44 Mon Sep 17 00:00:00 2001
From: Dario Nieuwenhuis <dirbaio@dirbaio.net>
Date: Sun, 19 Dec 2021 09:20:20 +0100
Subject: [PATCH 3/8] spi/blocking: group methods into read-only, write-only
 and read-write traits.

---
 src/spi/blocking.rs | 84 ++++++++++++++++++---------------------------
 1 file changed, 34 insertions(+), 50 deletions(-)

diff --git a/src/spi/blocking.rs b/src/spi/blocking.rs
index b2e9b9ee9..9b07bfc0f 100644
--- a/src/spi/blocking.rs
+++ b/src/spi/blocking.rs
@@ -2,40 +2,7 @@
 
 use super::ErrorType;
 
-/// Blocking transfer with separate buffers
-pub trait Transfer<W = u8>: ErrorType {
-    /// Writes and reads simultaneously. `write` is written to the slave on MOSI and
-    /// words received on MISO are stored in `read`.
-    ///
-    /// It is allowed for `read` and `write` to have different lengths, even zero length.
-    /// The transfer runs for `max(read.len(), write.len())` words. If `read` is shorter,
-    /// incoming words after `read` has been filled will be discarded. If `write` is shorter,
-    /// the value of words sent in MOSI after all `write` has been sent is implementation-defined,
-    /// typically `0x00`, `0xFF`, or configurable.
-    fn transfer(&mut self, read: &mut [W], write: &[W]) -> Result<(), Self::Error>;
-}
-
-impl<T: Transfer<W>, W> Transfer<W> for &mut T {
-    fn transfer(&mut self, read: &mut [W], write: &[W]) -> Result<(), Self::Error> {
-        T::transfer(self, read, write)
-    }
-}
-
-/// Blocking transfer with single buffer (in-place)
-pub trait TransferInplace<W = u8>: ErrorType {
-    /// Writes and reads simultaneously. The contents of `words` are
-    /// written to the slave, and the received words are stored into the same
-    /// `words` buffer, overwriting it.
-    fn transfer_inplace(&mut self, words: &mut [W]) -> Result<(), Self::Error>;
-}
-
-impl<T: TransferInplace<W>, W> TransferInplace<W> for &mut T {
-    fn transfer_inplace(&mut self, words: &mut [W]) -> Result<(), Self::Error> {
-        T::transfer_inplace(self, words)
-    }
-}
-
-/// Blocking read
+/// Blocking read-only SPI
 pub trait Read<W = u8>: ErrorType {
     /// Reads `words` from the slave.
     ///
@@ -50,27 +17,22 @@ impl<T: Read<W>, W> Read<W> for &mut T {
     }
 }
 
-/// Blocking write
+/// Blocking write-only SPI
 pub trait Write<W = u8>: ErrorType {
     /// Writes `words` to the slave, ignoring all the incoming words
     fn write(&mut self, words: &[W]) -> Result<(), Self::Error>;
-}
-
-impl<T: Write<W>, W> Write<W> for &mut T {
-    fn write(&mut self, words: &[W]) -> Result<(), Self::Error> {
-        T::write(self, words)
-    }
-}
 
-/// Blocking write (iterator version)
-pub trait WriteIter<W = u8>: ErrorType {
     /// Writes `words` to the slave, ignoring all the incoming words
     fn write_iter<WI>(&mut self, words: WI) -> Result<(), Self::Error>
     where
         WI: IntoIterator<Item = W>;
 }
 
-impl<T: WriteIter<W>, W> WriteIter<W> for &mut T {
+impl<T: Write<W>, W> Write<W> for &mut T {
+    fn write(&mut self, words: &[W]) -> Result<(), Self::Error> {
+        T::write(self, words)
+    }
+
     fn write_iter<WI>(&mut self, words: WI) -> Result<(), Self::Error>
     where
         WI: IntoIterator<Item = W>,
@@ -94,14 +56,36 @@ pub enum Operation<'a, W: 'static = u8> {
     TransferInplace(&'a mut [W]),
 }
 
-/// Transactional trait allows multiple actions to be executed
-/// as part of a single SPI transaction
-pub trait Transactional<W: 'static = u8>: ErrorType {
-    /// Execute the provided transactions
+/// Blocking read-write SPI
+pub trait ReadWrite<W = u8>: Read<W> + Write<W> {
+    /// Writes and reads simultaneously. `write` is written to the slave on MOSI and
+    /// words received on MISO are stored in `read`.
+    ///
+    /// It is allowed for `read` and `write` to have different lengths, even zero length.
+    /// The transfer runs for `max(read.len(), write.len())` words. If `read` is shorter,
+    /// incoming words after `read` has been filled will be discarded. If `write` is shorter,
+    /// the value of words sent in MOSI after all `write` has been sent is implementation-defined,
+    /// typically `0x00`, `0xFF`, or configurable.
+    fn transfer(&mut self, read: &mut [W], write: &[W]) -> Result<(), Self::Error>;
+
+    /// Writes and reads simultaneously. The contents of `words` are
+    /// written to the slave, and the received words are stored into the same
+    /// `words` buffer, overwriting it.
+    fn transfer_inplace(&mut self, words: &mut [W]) -> Result<(), Self::Error>;
+
+    /// Execute multiple actions as part of a single SPI transaction
     fn exec<'a>(&mut self, operations: &mut [Operation<'a, W>]) -> Result<(), Self::Error>;
 }
 
-impl<T: Transactional<W>, W: 'static> Transactional<W> for &mut T {
+impl<T: ReadWrite<W>, W> ReadWrite<W> for &mut T {
+    fn transfer(&mut self, read: &mut [W], write: &[W]) -> Result<(), Self::Error> {
+        T::transfer(self, read, write)
+    }
+
+    fn transfer_inplace(&mut self, words: &mut [W]) -> Result<(), Self::Error> {
+        T::transfer_inplace(self, words)
+    }
+
     fn exec<'a>(&mut self, operations: &mut [Operation<'a, W>]) -> Result<(), Self::Error> {
         T::exec(self, operations)
     }

From 33073081f8432eca55c78d536be43fd7baf1d38e Mon Sep 17 00:00:00 2001
From: Dario Nieuwenhuis <dirbaio@dirbaio.net>
Date: Wed, 3 Nov 2021 15:24:35 +0100
Subject: [PATCH 4/8] spi/blocking: add read_batch, write_batch.

---
 src/spi/blocking.rs | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/src/spi/blocking.rs b/src/spi/blocking.rs
index 9b07bfc0f..292373a04 100644
--- a/src/spi/blocking.rs
+++ b/src/spi/blocking.rs
@@ -9,12 +9,22 @@ pub trait Read<W = u8>: ErrorType {
     /// The word value sent on MOSI during reading is implementation-defined,
     /// typically `0x00`, `0xFF`, or configurable.
     fn read(&mut self, words: &mut [W]) -> Result<(), Self::Error>;
+
+    /// Reads all slices in `words` from the slave as part of a single SPI transaction.
+    ///
+    /// The word value sent on MOSI during reading is implementation-defined,
+    /// typically `0x00`, `0xFF`, or configurable.
+    fn read_batch(&mut self, words: &mut [&mut [W]]) -> Result<(), Self::Error>;
 }
 
 impl<T: Read<W>, W> Read<W> for &mut T {
     fn read(&mut self, words: &mut [W]) -> Result<(), Self::Error> {
         T::read(self, words)
     }
+
+    fn read_batch(&mut self, words: &mut [&mut [W]]) -> Result<(), Self::Error> {
+        T::read_batch(self, words)
+    }
 }
 
 /// Blocking write-only SPI
@@ -22,6 +32,9 @@ pub trait Write<W = u8>: ErrorType {
     /// Writes `words` to the slave, ignoring all the incoming words
     fn write(&mut self, words: &[W]) -> Result<(), Self::Error>;
 
+    /// Writes all slices in `words` to the slave as part of a single SPI transaction, ignoring all the incoming words
+    fn write_batch(&mut self, words: &[&[W]]) -> Result<(), Self::Error>;
+
     /// Writes `words` to the slave, ignoring all the incoming words
     fn write_iter<WI>(&mut self, words: WI) -> Result<(), Self::Error>
     where
@@ -33,6 +46,10 @@ impl<T: Write<W>, W> Write<W> for &mut T {
         T::write(self, words)
     }
 
+    fn write_batch(&mut self, words: &[&[W]]) -> Result<(), Self::Error> {
+        T::write_batch(self, words)
+    }
+
     fn write_iter<WI>(&mut self, words: WI) -> Result<(), Self::Error>
     where
         WI: IntoIterator<Item = W>,

From 63dd044938c7557ff05c9b0cf8a5a287580a21f3 Mon Sep 17 00:00:00 2001
From: Dario Nieuwenhuis <dirbaio@dirbaio.net>
Date: Wed, 3 Nov 2021 15:24:41 +0100
Subject: [PATCH 5/8] spi/blocking: rename exec to batch

---
 src/spi/blocking.rs | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/src/spi/blocking.rs b/src/spi/blocking.rs
index 292373a04..e43278687 100644
--- a/src/spi/blocking.rs
+++ b/src/spi/blocking.rs
@@ -58,7 +58,7 @@ impl<T: Write<W>, W> Write<W> for &mut T {
     }
 }
 
-/// Operation for transactional SPI trait
+/// Operation for ReadWrite::batch
 ///
 /// This allows composition of SPI operations into a single bus transaction
 #[derive(Debug, PartialEq)]
@@ -91,7 +91,7 @@ pub trait ReadWrite<W = u8>: Read<W> + Write<W> {
     fn transfer_inplace(&mut self, words: &mut [W]) -> Result<(), Self::Error>;
 
     /// Execute multiple actions as part of a single SPI transaction
-    fn exec<'a>(&mut self, operations: &mut [Operation<'a, W>]) -> Result<(), Self::Error>;
+    fn batch<'a>(&mut self, operations: &mut [Operation<'a, W>]) -> Result<(), Self::Error>;
 }
 
 impl<T: ReadWrite<W>, W> ReadWrite<W> for &mut T {
@@ -103,7 +103,7 @@ impl<T: ReadWrite<W>, W> ReadWrite<W> for &mut T {
         T::transfer_inplace(self, words)
     }
 
-    fn exec<'a>(&mut self, operations: &mut [Operation<'a, W>]) -> Result<(), Self::Error> {
-        T::exec(self, operations)
+    fn batch<'a>(&mut self, operations: &mut [Operation<'a, W>]) -> Result<(), Self::Error> {
+        T::batch(self, operations)
     }
 }

From 74e9373f95220f3a4ea9bcc83989a8eac101b305 Mon Sep 17 00:00:00 2001
From: Dario Nieuwenhuis <dirbaio@dirbaio.net>
Date: Tue, 23 Nov 2021 21:12:42 +0100
Subject: [PATCH 6/8] Add changelog.

---
 CHANGELOG.md | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 078bd683b..8ac881cb1 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -12,6 +12,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
 
 ### Changed
 - `spi`: traits now enforce all impls on the same struct (eg `Transfer` and `Write`) have the same `Error` type. 
+- `spi/blocking`: unified traits into `Read`, `Write`, `ReadWrite`.
+- `spi/blocking`: renamed Transactional `exec` to `batch`.
+- `spi/blocking`: Added `read_batch`, `write_batch` methods.
 
 ## [v1.0.0-alpha.6] - 2021-11-19
 

From 02f1371a261a23fe2b5b01162ead1c01bec92919 Mon Sep 17 00:00:00 2001
From: Dario Nieuwenhuis <dirbaio@dirbaio.net>
Date: Sun, 19 Dec 2021 22:33:18 +0100
Subject: [PATCH 7/8] spi: rename inplace -> in_place

---
 src/spi/blocking.rs | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/src/spi/blocking.rs b/src/spi/blocking.rs
index e43278687..0fb169e41 100644
--- a/src/spi/blocking.rs
+++ b/src/spi/blocking.rs
@@ -70,7 +70,7 @@ pub enum Operation<'a, W: 'static = u8> {
     /// Write data out while reading data into the provided buffer
     Transfer(&'a mut [W], &'a [W]),
     /// Write data out while reading data into the provided buffer
-    TransferInplace(&'a mut [W]),
+    TransferInPlace(&'a mut [W]),
 }
 
 /// Blocking read-write SPI
@@ -88,7 +88,7 @@ pub trait ReadWrite<W = u8>: Read<W> + Write<W> {
     /// Writes and reads simultaneously. The contents of `words` are
     /// written to the slave, and the received words are stored into the same
     /// `words` buffer, overwriting it.
-    fn transfer_inplace(&mut self, words: &mut [W]) -> Result<(), Self::Error>;
+    fn transfer_in_place(&mut self, words: &mut [W]) -> Result<(), Self::Error>;
 
     /// Execute multiple actions as part of a single SPI transaction
     fn batch<'a>(&mut self, operations: &mut [Operation<'a, W>]) -> Result<(), Self::Error>;
@@ -99,8 +99,8 @@ impl<T: ReadWrite<W>, W> ReadWrite<W> for &mut T {
         T::transfer(self, read, write)
     }
 
-    fn transfer_inplace(&mut self, words: &mut [W]) -> Result<(), Self::Error> {
-        T::transfer_inplace(self, words)
+    fn transfer_in_place(&mut self, words: &mut [W]) -> Result<(), Self::Error> {
+        T::transfer_in_place(self, words)
     }
 
     fn batch<'a>(&mut self, operations: &mut [Operation<'a, W>]) -> Result<(), Self::Error> {

From 519e99c91907adf8c1cc06dcc88845ca96e4a366 Mon Sep 17 00:00:00 2001
From: Dario Nieuwenhuis <dirbaio@dirbaio.net>
Date: Sun, 19 Dec 2021 09:54:26 +0100
Subject: [PATCH 8/8] Add embedded-hal-async crate.

Co-authored-by: Lachlan Sneff <lachlan.sneff@gmail.com>
---
 .gitignore                        |   2 +-
 embedded-hal-async/Cargo.toml     |  15 +++
 embedded-hal-async/src/delay.rs   |  52 ++++++++++
 embedded-hal-async/src/digital.rs | 100 ++++++++++++++++++
 embedded-hal-async/src/i2c.rs     | 163 ++++++++++++++++++++++++++++++
 embedded-hal-async/src/lib.rs     |  13 +++
 embedded-hal-async/src/serial.rs  |  74 ++++++++++++++
 embedded-hal-async/src/spi.rs     | 157 ++++++++++++++++++++++++++++
 8 files changed, 575 insertions(+), 1 deletion(-)
 create mode 100644 embedded-hal-async/Cargo.toml
 create mode 100644 embedded-hal-async/src/delay.rs
 create mode 100644 embedded-hal-async/src/digital.rs
 create mode 100644 embedded-hal-async/src/i2c.rs
 create mode 100644 embedded-hal-async/src/lib.rs
 create mode 100644 embedded-hal-async/src/serial.rs
 create mode 100644 embedded-hal-async/src/spi.rs

diff --git a/.gitignore b/.gitignore
index f8d7c8b49..7f487cce0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,4 @@
 **/*.rs.bk
 .#*
-/target/
+target
 Cargo.lock
diff --git a/embedded-hal-async/Cargo.toml b/embedded-hal-async/Cargo.toml
new file mode 100644
index 000000000..6226f7e50
--- /dev/null
+++ b/embedded-hal-async/Cargo.toml
@@ -0,0 +1,15 @@
+[package]
+name = "embedded-hal-async"
+version = "0.1.0"
+edition = "2021"
+categories = ["asynchronous", "embedded", "hardware-support", "no-std"]
+description = " A Hardware Abstraction Layer (HAL) for embedded systems, async version"
+documentation = "https://docs.rs/embedded-hal-async"
+keywords = ["hal", "IO", "async"]
+license = "MIT OR Apache-2.0"
+readme = "README.md"
+repository = "https://github.com/rust-embedded/embedded-hal"
+
+[dependencies]
+nb = "1"
+embedded-hal = { version = "1.0.0-alpha.6", path = ".." }
\ No newline at end of file
diff --git a/embedded-hal-async/src/delay.rs b/embedded-hal-async/src/delay.rs
new file mode 100644
index 000000000..a7b8f6313
--- /dev/null
+++ b/embedded-hal-async/src/delay.rs
@@ -0,0 +1,52 @@
+//! Delays
+
+use core::future::Future;
+
+/// Microsecond delay
+pub trait DelayUs {
+    /// Enumeration of errors
+    type Error: core::fmt::Debug;
+
+    /// The future returned by the `delay_us` function.
+    type DelayUsFuture<'a>: Future<Output = Result<(), Self::Error>> + 'a
+    where
+        Self: 'a;
+
+    /// 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) -> Self::DelayUsFuture<'_>;
+
+    /// The future returned by the `delay_ms` function.
+    type DelayMsFuture<'a>: Future<Output = Result<(), Self::Error>> + 'a
+    where
+        Self: 'a;
+
+    /// Pauses execution for at minimum `ms` milliseconds. Pause can be longer
+    /// if the implementation requires it due to precision/timing issues.
+    fn delay_ms(&mut self, ms: u32) -> Self::DelayMsFuture<'_>;
+}
+
+impl<T> DelayUs for &mut T
+where
+    T: DelayUs,
+{
+    type Error = T::Error;
+
+    type DelayUsFuture<'a>
+    where
+        Self: 'a,
+    = T::DelayUsFuture<'a>;
+
+    fn delay_us(&mut self, us: u32) -> Self::DelayUsFuture<'_> {
+        T::delay_us(self, us)
+    }
+
+    type DelayMsFuture<'a>
+    where
+        Self: 'a,
+    = T::DelayMsFuture<'a>;
+
+    fn delay_ms(&mut self, ms: u32) -> Self::DelayMsFuture<'_> {
+        T::delay_ms(self, ms)
+    }
+}
diff --git a/embedded-hal-async/src/digital.rs b/embedded-hal-async/src/digital.rs
new file mode 100644
index 000000000..ae1d6c543
--- /dev/null
+++ b/embedded-hal-async/src/digital.rs
@@ -0,0 +1,100 @@
+//! Asynchronous digital I/O
+//!
+//! # Example
+//!
+//! ```rust
+//! # use embedded_hal_async::digital::WaitForHigh;
+//! /// Asynchronously wait until the `ready_pin` becomes high.
+//! async fn wait_until_ready<P>(ready_pin: &mut P)
+//! where
+//!     P: WaitForHigh,
+//! {
+//!     ready_pin
+//!         .wait_for_high()
+//!         .await
+//!         .expect("failed to await input pin")
+//! }
+//! ```
+
+use core::future::Future;
+
+/// Asynchronously wait for a pin to be high.
+pub trait WaitForHigh {
+    /// Enumeration of errors.
+    type Error: core::fmt::Debug;
+
+    /// The future returned by the `wait_for_high` function.
+    type WaitForHighFuture<'a>: Future<Output = Result<(), Self::Error>> + 'a
+    where
+        Self: 'a;
+
+    /// Returns a future that resolves when this pin _is_ high. If the pin
+    /// is already high, the future resolves immediately.
+    ///
+    /// # Note for implementers
+    /// The pin may have switched back to low before the task was run after
+    /// being woken. The future should still resolve in that case.
+    fn wait_for_high<'a>(&'a mut self) -> Self::WaitForHighFuture<'a>;
+}
+
+/// Asynchronously wait for a pin to be low.
+pub trait WaitForLow {
+    /// Enumeration of errors.
+    type Error: core::fmt::Debug;
+
+    /// The future returned by `wait_for_low`.
+    type WaitForLowFuture<'a>: Future<Output = Result<(), Self::Error>> + 'a
+    where
+        Self: 'a;
+
+    /// Returns a future that resolves when this pin _is_ low. If the pin
+    /// is already low, the future resolves immediately.
+    ///
+    /// # Note for implementers
+    /// The pin may have switched back to high before the task was run after
+    /// being woken. The future should still resolve in that case.
+    fn wait_for_low<'a>(&'a mut self) -> Self::WaitForLowFuture<'a>;
+}
+
+/// Wait for a rising edge (transition from low to high).
+pub trait WaitForRisingEdge {
+    /// Enumeration of errors.
+    type Error: core::fmt::Debug;
+
+    /// The future returned from `wait_for_rising_edge`.
+    type WaitForRisingEdgeFuture<'a>: Future<Output = Result<(), Self::Error>> + 'a
+    where
+        Self: 'a;
+
+    /// Returns a future that resolves when this pin transitions from low to high.
+    fn wait_for_rising_edge<'a>(&'a mut self) -> Self::WaitForRisingEdgeFuture<'a>;
+}
+
+/// Wait for a falling edge (transition from high to low).
+pub trait WaitForFallingEdge {
+    /// Enumeration of errors.
+    type Error: core::fmt::Debug;
+
+    /// The future returned from `wait_for_falling_edge`.
+    type WaitForFallingEdgeFuture<'a>: Future<Output = Result<(), Self::Error>> + 'a
+    where
+        Self: 'a;
+
+    /// Returns a future that resolves when this pin transitions from high to low.
+    fn wait_for_falling_edge<'a>(&'a mut self) -> Self::WaitForFallingEdgeFuture<'a>;
+}
+
+/// Wait for any edge (transition from low to high OR high to low).
+pub trait WaitForAnyEdge {
+    /// Enumeration of errors.
+    type Error: core::fmt::Debug;
+
+    /// The future returned from `wait_for_any_edge`.
+    type WaitForAnyEdgeFuture<'a>: Future<Output = Result<(), Self::Error>> + 'a
+    where
+        Self: 'a;
+
+    /// Returns a future that resolves when this pin undergoes any transition, e.g.
+    /// low to high OR high to low.
+    fn wait_for_any_edge<'a>(&'a mut self) -> Self::WaitForAnyEdgeFuture<'a>;
+}
diff --git a/embedded-hal-async/src/i2c.rs b/embedded-hal-async/src/i2c.rs
new file mode 100644
index 000000000..ef0718757
--- /dev/null
+++ b/embedded-hal-async/src/i2c.rs
@@ -0,0 +1,163 @@
+//! 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.
+
+use core::future::Future;
+pub use embedded_hal::i2c::{
+    AddressMode, Error, ErrorKind, NoAcknowledgeSource, SevenBitAddress, TenBitAddress,
+};
+
+/// Async read
+pub trait Read<A: AddressMode = SevenBitAddress> {
+    /// Error type
+    type Error: Error;
+    /// The future associated with the `read` method.
+    type ReadFuture<'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, read: &'a mut [u8]) -> Self::ReadFuture<'a>;
+}
+
+impl<A: AddressMode, T: Read<A>> Read<A> for &mut T {
+    type Error = T::Error;
+
+    type ReadFuture<'a>
+    where
+        Self: 'a,
+    = T::ReadFuture<'a>;
+
+    fn read<'a>(&'a mut self, address: A, buffer: &'a mut [u8]) -> Self::ReadFuture<'a> {
+        T::read(self, address, buffer)
+    }
+}
+
+/// Async write
+pub trait Write<A: AddressMode = SevenBitAddress> {
+    /// Error type
+    type Error: Error;
+    /// The future associated with the `write` method.
+    type WriteFuture<'a>: Future<Output = Result<(), Self::Error>> + 'a
+    where
+        Self: 'a;
+
+    /// Writes 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, write: &'a [u8]) -> Self::WriteFuture<'a>;
+}
+
+impl<A: AddressMode, T: Write<A>> Write<A> for &mut T {
+    type Error = T::Error;
+
+    type WriteFuture<'a>
+    where
+        Self: 'a,
+    = T::WriteFuture<'a>;
+
+    fn write<'a>(&'a mut self, address: A, bytes: &'a [u8]) -> Self::WriteFuture<'a> {
+        T::write(self, address, bytes)
+    }
+}
+
+/// Async write + read
+pub trait WriteRead<A: AddressMode = SevenBitAddress> {
+    /// Error type
+    type Error: Error;
+    /// The future associated with the `write_read` method.
+    type WriteReadFuture<'a>: Future<Output = Result<(), Self::Error>> + 'a
+    where
+        Self: 'a;
+
+    /// Writes bytes to slave with address `address` and then reads enough bytes to fill `read` *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,
+        write: &'a [u8],
+        read: &'a mut [u8],
+    ) -> Self::WriteReadFuture<'a>;
+}
+
+impl<A: AddressMode, T: WriteRead<A>> WriteRead<A> for &mut T {
+    type Error = T::Error;
+
+    type WriteReadFuture<'a>
+    where
+        Self: 'a,
+    = T::WriteReadFuture<'a>;
+
+    fn write_read<'a>(
+        &'a mut self,
+        address: A,
+        bytes: &'a [u8],
+        buffer: &'a mut [u8],
+    ) -> Self::WriteReadFuture<'a> {
+        T::write_read(self, address, bytes, buffer)
+    }
+}
diff --git a/embedded-hal-async/src/lib.rs b/embedded-hal-async/src/lib.rs
new file mode 100644
index 000000000..1026b5fc5
--- /dev/null
+++ b/embedded-hal-async/src/lib.rs
@@ -0,0 +1,13 @@
+#![feature(generic_associated_types)]
+#![no_std]
+#![deny(missing_docs)]
+
+//! Asynchronous APIs
+//!
+//! This traits use `core::future::Future` and generic associated types.
+
+pub mod delay;
+pub mod digital;
+pub mod i2c;
+pub mod serial;
+pub mod spi;
diff --git a/embedded-hal-async/src/serial.rs b/embedded-hal-async/src/serial.rs
new file mode 100644
index 000000000..95bc2cea3
--- /dev/null
+++ b/embedded-hal-async/src/serial.rs
@@ -0,0 +1,74 @@
+//! Serial interface
+
+use core::future::Future;
+pub use embedded_hal::serial::{Error, ErrorKind};
+
+/// Read half of a serial interface
+///
+/// Some serial interfaces support different data sizes (8 bits, 9 bits, etc.);
+/// This can be encoded in this trait via the `Word` type parameter.
+pub trait Read<Word: 'static = u8> {
+    /// Read error
+    type Error: Error;
+
+    /// The future associated with the `read` method.
+    type ReadFuture<'a>: Future<Output = Result<(), Self::Error>> + 'a
+    where
+        Self: 'a;
+
+    /// Reads words from the serial interface into the supplied slice.
+    fn read<'a>(&'a mut self, read: &'a mut [Word]) -> Self::ReadFuture<'a>;
+}
+
+impl<T: Read<Word>, Word: 'static> Read<Word> for &mut T {
+    type Error = T::Error;
+    type ReadFuture<'a>
+    where
+        Self: 'a,
+    = T::ReadFuture<'a>;
+
+    fn read<'a>(&'a mut self, read: &'a mut [Word]) -> Self::ReadFuture<'a> {
+        T::read(self, read)
+    }
+}
+/// Write half of a serial interface
+pub trait Write<Word: 'static = u8> {
+    /// Write error
+    type Error: Error;
+
+    /// The future associated with the `write` method.
+    type WriteFuture<'a>: Future<Output = Result<(), Self::Error>> + 'a
+    where
+        Self: 'a;
+
+    /// The future associated with the `flush` method.
+    type FlushFuture<'a>: Future<Output = Result<(), Self::Error>> + 'a
+    where
+        Self: 'a;
+
+    /// Writes a single word to the serial interface
+    fn write<'a>(&'a mut self, words: &'a [Word]) -> Self::WriteFuture<'a>;
+
+    /// Ensures that none of the previously written words are still buffered
+    fn flush<'a>(&'a mut self) -> Self::FlushFuture<'a>;
+}
+
+impl<T: Write<Word>, Word: 'static> Write<Word> for &mut T {
+    type Error = T::Error;
+    type WriteFuture<'a>
+    where
+        Self: 'a,
+    = T::WriteFuture<'a>;
+    type FlushFuture<'a>
+    where
+        Self: 'a,
+    = T::FlushFuture<'a>;
+
+    fn write<'a>(&'a mut self, words: &'a [Word]) -> Self::WriteFuture<'a> {
+        T::write(self, words)
+    }
+
+    fn flush<'a>(&'a mut self) -> Self::FlushFuture<'a> {
+        T::flush(self)
+    }
+}
diff --git a/embedded-hal-async/src/spi.rs b/embedded-hal-async/src/spi.rs
new file mode 100644
index 000000000..2a6d79697
--- /dev/null
+++ b/embedded-hal-async/src/spi.rs
@@ -0,0 +1,157 @@
+//! Serial Peripheral Interface
+
+use core::future::Future;
+
+pub use embedded_hal::spi::blocking::Operation;
+pub use embedded_hal::spi::{
+    Error, ErrorKind, ErrorType, Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3,
+};
+
+/// Read-only SPI
+pub trait Read<W: 'static = u8>: ErrorType {
+    /// Associated future for the `read` method.
+    type ReadFuture<'a>: Future<Output = Result<(), Self::Error>> + 'a
+    where
+        Self: 'a;
+
+    /// Reads `words` from the slave.
+    ///
+    /// The word value sent on MOSI during reading is implementation-defined,
+    /// typically `0x00`, `0xFF`, or configurable.
+    fn read<'a>(&'a mut self, words: &'a mut [W]) -> Self::ReadFuture<'a>;
+
+    /// Associated future for the `read_batch` method.
+    type ReadBatchFuture<'a>: Future<Output = Result<(), Self::Error>> + 'a
+    where
+        Self: 'a;
+
+    /// Reads all slices in `words` from the slave as part of a single SPI transaction.
+    ///
+    /// The word value sent on MOSI during reading is implementation-defined,
+    /// typically `0x00`, `0xFF`, or configurable.
+    fn read_batch<'a>(&'a mut self, words: &'a mut [&'a mut [W]]) -> Self::ReadBatchFuture<'a>;
+}
+
+impl<T: Read<W>, W: 'static> Read<W> for &mut T {
+    type ReadFuture<'a>
+    where
+        Self: 'a,
+    = T::ReadFuture<'a>;
+
+    fn read<'a>(&'a mut self, words: &'a mut [W]) -> Self::ReadFuture<'a> {
+        T::read(self, words)
+    }
+
+    type ReadBatchFuture<'a>
+    where
+        Self: 'a,
+    = T::ReadBatchFuture<'a>;
+
+    fn read_batch<'a>(&'a mut self, words: &'a mut [&'a mut [W]]) -> Self::ReadBatchFuture<'a> {
+        T::read_batch(self, words)
+    }
+}
+
+/// Write-only SPI
+pub trait Write<W: 'static = u8>: ErrorType {
+    /// Associated future for the `write` method.
+    type WriteFuture<'a>: Future<Output = Result<(), Self::Error>> + 'a
+    where
+        Self: 'a;
+
+    /// Writes `words` to the slave, ignoring all the incoming words
+    fn write<'a>(&'a mut self, words: &'a [W]) -> Self::WriteFuture<'a>;
+
+    /// Associated future for the `write_batch` method.
+    type WriteBatchFuture<'a>: Future<Output = Result<(), Self::Error>> + 'a
+    where
+        Self: 'a;
+
+    /// Writes all slices in `words` to the slave as part of a single SPI transaction, ignoring all the incoming words
+    fn write_batch<'a>(&'a mut self, words: &'a [&'a [W]]) -> Self::WriteBatchFuture<'a>;
+}
+
+impl<T: Write<W>, W: 'static> Write<W> for &mut T {
+    type WriteFuture<'a>
+    where
+        Self: 'a,
+    = T::WriteFuture<'a>;
+
+    fn write<'a>(&'a mut self, words: &'a [W]) -> Self::WriteFuture<'a> {
+        T::write(self, words)
+    }
+
+    type WriteBatchFuture<'a>
+    where
+        Self: 'a,
+    = T::WriteBatchFuture<'a>;
+
+    fn write_batch<'a>(&'a mut self, words: &'a [&'a [W]]) -> Self::WriteBatchFuture<'a> {
+        T::write_batch(self, words)
+    }
+}
+
+/// Read-write SPI
+pub trait ReadWrite<W: 'static = u8>: Read<W> + Write<W> {
+    /// Associated future for the `transfer` method.
+    type TransferFuture<'a>: Future<Output = Result<(), Self::Error>> + 'a
+    where
+        Self: 'a;
+
+    /// Writes and reads simultaneously. `write` is written to the slave on MOSI and
+    /// words received on MISO are stored in `read`.
+    ///
+    /// It is allowed for `read` and `write` to have different lengths, even zero length.
+    /// The transfer runs for `max(read.len(), write.len())` words. If `read` is shorter,
+    /// incoming words after `read` has been filled will be discarded. If `write` is shorter,
+    /// the value of words sent in MOSI after all `write` has been sent is implementation-defined,
+    /// typically `0x00`, `0xFF`, or configurable.
+    fn transfer<'a>(&'a mut self, read: &'a mut [W], write: &'a [W]) -> Self::TransferFuture<'a>;
+
+    /// Associated future for the `transfer_in_place` method.
+    type TransferInPlaceFuture<'a>: Future<Output = Result<(), Self::Error>> + 'a
+    where
+        Self: 'a;
+
+    /// Writes and reads simultaneously. The contents of `words` are
+    /// written to the slave, and the received words are stored into the same
+    /// `words` buffer, overwriting it.
+    fn transfer_in_place<'a>(&'a mut self, words: &'a mut [W]) -> Self::TransferInPlaceFuture<'a>;
+
+    /// Associated future for the `batch` method.
+    type BatchFuture<'a>: Future<Output = Result<(), Self::Error>> + 'a
+    where
+        Self: 'a;
+
+    /// Execute multiple actions as part of a single SPI transaction
+    fn batch<'a>(&'a mut self, operations: &'a mut [Operation<'a, W>]) -> Self::BatchFuture<'a>;
+}
+
+impl<T: ReadWrite<W>, W: 'static> ReadWrite<W> for &mut T {
+    type TransferFuture<'a>
+    where
+        Self: 'a,
+    = T::TransferFuture<'a>;
+
+    fn transfer<'a>(&'a mut self, read: &'a mut [W], write: &'a [W]) -> Self::TransferFuture<'a> {
+        T::transfer(self, read, write)
+    }
+
+    type TransferInPlaceFuture<'a>
+    where
+        Self: 'a,
+    = T::TransferInPlaceFuture<'a>;
+
+    fn transfer_in_place<'a>(&'a mut self, words: &'a mut [W]) -> Self::TransferInPlaceFuture<'a> {
+        T::transfer_in_place(self, words)
+    }
+
+    type BatchFuture<'a>
+    where
+        Self: 'a,
+    = T::BatchFuture<'a>;
+
+    fn batch<'a>(&'a mut self, operations: &'a mut [Operation<'a, W>]) -> Self::BatchFuture<'a> {
+        T::batch(self, operations)
+    }
+}