aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-stm32/Cargo.toml1
-rw-r--r--embassy-stm32/src/usart/mod.rs31
-rw-r--r--embassy-traits/Cargo.toml1
-rw-r--r--embassy-traits/src/adapter.rs166
-rw-r--r--embassy-traits/src/lib.rs1
-rw-r--r--examples/stm32l4/src/bin/i2c_blocking_async.rs29
-rw-r--r--examples/stm32l4/src/bin/spi_blocking_async.rs57
-rw-r--r--examples/stm32l4/src/bin/usart_blocking_async.rs32
8 files changed, 316 insertions, 2 deletions
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml
index 135f9a918..264005850 100644
--- a/embassy-stm32/Cargo.toml
+++ b/embassy-stm32/Cargo.toml
@@ -27,6 +27,7 @@ atomic-polyfill = "0.1.5"
27stm32-metapac = { version = "0.1.0", path = "../stm32-metapac", features = ["rt"] } 27stm32-metapac = { version = "0.1.0", path = "../stm32-metapac", features = ["rt"] }
28vcell = { version = "0.1.3", optional = true } 28vcell = { version = "0.1.3", optional = true }
29bxcan = "0.6.2" 29bxcan = "0.6.2"
30nb = "1.0.0"
30 31
31seq-macro = "0.2.2" 32seq-macro = "0.2.2"
32 33
diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs
index 3567746cf..e46e14eec 100644
--- a/embassy-stm32/src/usart/mod.rs
+++ b/embassy-stm32/src/usart/mod.rs
@@ -192,8 +192,35 @@ impl<'d, T: Instance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
192 } 192 }
193} 193}
194 194
195impl<'d, T: Instance, RxDma> embedded_hal::blocking::serial::Write<u8> 195impl<'d, T: Instance, TxDma, RxDma> embedded_hal::serial::Read<u8> for Uart<'d, T, TxDma, RxDma> {
196 for Uart<'d, T, NoDma, RxDma> 196 type Error = Error;
197 fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> {
198 let r = self.inner.regs();
199 unsafe {
200 let sr = sr(r).read();
201 if sr.pe() {
202 rdr(r).read_volatile();
203 Err(nb::Error::Other(Error::Parity))
204 } else if sr.fe() {
205 rdr(r).read_volatile();
206 Err(nb::Error::Other(Error::Framing))
207 } else if sr.ne() {
208 rdr(r).read_volatile();
209 Err(nb::Error::Other(Error::Noise))
210 } else if sr.ore() {
211 rdr(r).read_volatile();
212 Err(nb::Error::Other(Error::Overrun))
213 } else if sr.rxne() {
214 Ok(rdr(r).read_volatile())
215 } else {
216 Err(nb::Error::WouldBlock)
217 }
218 }
219 }
220}
221
222impl<'d, T: Instance, TxDma, RxDma> embedded_hal::blocking::serial::Write<u8>
223 for Uart<'d, T, TxDma, RxDma>
197{ 224{
198 type Error = Error; 225 type Error = Error;
199 fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> { 226 fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> {
diff --git a/embassy-traits/Cargo.toml b/embassy-traits/Cargo.toml
index c98b583e5..a93cb3c54 100644
--- a/embassy-traits/Cargo.toml
+++ b/embassy-traits/Cargo.toml
@@ -10,3 +10,4 @@ std = []
10[dependencies] 10[dependencies]
11defmt = { version = "0.3", optional = true } 11defmt = { version = "0.3", optional = true }
12embedded-hal = { version = "0.2.6", features = ["unproven"] } 12embedded-hal = { version = "0.2.6", features = ["unproven"] }
13nb = "1.0.0"
diff --git a/embassy-traits/src/adapter.rs b/embassy-traits/src/adapter.rs
new file mode 100644
index 000000000..ce7dd411f
--- /dev/null
+++ b/embassy-traits/src/adapter.rs
@@ -0,0 +1,166 @@
1use core::future::Future;
2use embedded_hal::blocking;
3use embedded_hal::serial;
4
5/// BlockingAsync is a wrapper that implements async traits using blocking peripherals. This allows
6/// driver writers to depend on the async traits while still supporting embedded-hal peripheral implementations.
7///
8/// BlockingAsync will implement any async trait that maps to embedded-hal traits implemented for the wrapped driver.
9///
10/// Driver users are then free to choose which implementation that is available to them.
11pub struct BlockingAsync<T> {
12 wrapped: T,
13}
14
15impl<T> BlockingAsync<T> {
16 /// Create a new instance of a wrapper for a given peripheral.
17 pub fn new(wrapped: T) -> Self {
18 Self { wrapped }
19 }
20}
21
22//
23// I2C implementatinos
24//
25
26impl<T, E> crate::i2c::I2c for BlockingAsync<T>
27where
28 E: 'static,
29 T: blocking::i2c::WriteRead<Error = E>
30 + blocking::i2c::Read<Error = E>
31 + blocking::i2c::Write<Error = E>,
32{
33 type Error = E;
34
35 #[rustfmt::skip]
36 type WriteFuture<'a> where Self: 'a = impl Future<Output = Result<(), Self::Error>> + 'a;
37 #[rustfmt::skip]
38 type ReadFuture<'a> where Self: 'a = impl Future<Output = Result<(), Self::Error>> + 'a;
39 #[rustfmt::skip]
40 type WriteReadFuture<'a> where Self: 'a = impl Future<Output = Result<(), Self::Error>> + 'a;
41
42 fn read<'a>(&'a mut self, address: u8, buffer: &'a mut [u8]) -> Self::ReadFuture<'a> {
43 async move { self.wrapped.read(address, buffer) }
44 }
45
46 fn write<'a>(&'a mut self, address: u8, bytes: &'a [u8]) -> Self::WriteFuture<'a> {
47 async move { self.wrapped.write(address, bytes) }
48 }
49
50 fn write_read<'a>(
51 &'a mut self,
52 address: u8,
53 bytes: &'a [u8],
54 buffer: &'a mut [u8],
55 ) -> Self::WriteReadFuture<'a> {
56 async move { self.wrapped.write_read(address, bytes, buffer) }
57 }
58}
59
60//
61// SPI implementatinos
62//
63
64impl<T, E, Word> crate::spi::Spi<Word> for BlockingAsync<T>
65where
66 T: blocking::spi::Write<Word, Error = E>,
67{
68 type Error = E;
69}
70
71impl<T, E, Word> crate::spi::FullDuplex<Word> for BlockingAsync<T>
72where
73 E: 'static,
74 Word: Clone,
75 T: blocking::spi::Transfer<Word, Error = E> + blocking::spi::Write<Word, Error = E>,
76{
77 #[rustfmt::skip]
78 type WriteReadFuture<'a> where Word: 'a, Self: 'a = impl Future<Output = Result<(), Self::Error>> + 'a;
79
80 fn read_write<'a>(
81 &'a mut self,
82 read: &'a mut [Word],
83 write: &'a [Word],
84 ) -> Self::WriteReadFuture<'a> {
85 async move {
86 // Ensure we write the expected bytes
87 for i in 0..core::cmp::min(read.len(), write.len()) {
88 read[i] = write[i].clone();
89 }
90 self.wrapped.transfer(read)?;
91 Ok(())
92 }
93 }
94}
95
96impl<T, E, Word> crate::spi::Write<Word> for BlockingAsync<T>
97where
98 E: 'static,
99 Word: Clone,
100 T: blocking::spi::Write<Word, Error = E>,
101{
102 #[rustfmt::skip]
103 type WriteFuture<'a> where Word: 'a, Self: 'a = impl Future<Output = Result<(), Self::Error>> + 'a;
104
105 fn write<'a>(&'a mut self, data: &'a [Word]) -> Self::WriteFuture<'a> {
106 async move { self.wrapped.write(data) }
107 }
108}
109
110impl<T, E, Word> crate::spi::Read<Word> for BlockingAsync<T>
111where
112 E: 'static,
113 Word: Clone,
114 T: blocking::spi::Transfer<Word, Error = E> + blocking::spi::Write<Word, Error = E>,
115{
116 #[rustfmt::skip]
117 type ReadFuture<'a> where Word: 'a, Self: 'a = impl Future<Output = Result<(), Self::Error>> + 'a;
118
119 fn read<'a>(&'a mut self, data: &'a mut [Word]) -> Self::ReadFuture<'a> {
120 async move {
121 self.wrapped.transfer(data)?;
122 Ok(())
123 }
124 }
125}
126
127// Uart implementatinos
128impl<T> crate::uart::Read for BlockingAsync<T>
129where
130 T: serial::Read<u8>,
131{
132 #[rustfmt::skip]
133 type ReadFuture<'a> where T: 'a = impl Future<Output = Result<(), crate::uart::Error>> + 'a;
134 fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReadFuture<'a> {
135 async move {
136 let mut pos = 0;
137 while pos < buf.len() {
138 match self.wrapped.read() {
139 Err(nb::Error::WouldBlock) => {}
140 Err(_) => return Err(crate::uart::Error::Other),
141 Ok(b) => {
142 buf[pos] = b;
143 pos += 1;
144 }
145 }
146 }
147 Ok(())
148 }
149 }
150}
151
152impl<T> crate::uart::Write for BlockingAsync<T>
153where
154 T: blocking::serial::Write<u8>,
155{
156 #[rustfmt::skip]
157 type WriteFuture<'a> where T: 'a = impl Future<Output = Result<(), crate::uart::Error>> + 'a;
158 fn write<'a>(&'a mut self, buf: &'a [u8]) -> Self::WriteFuture<'a> {
159 async move {
160 self.wrapped
161 .bwrite_all(buf)
162 .map_err(|_| crate::uart::Error::Other)?;
163 self.wrapped.bflush().map_err(|_| crate::uart::Error::Other)
164 }
165 }
166}
diff --git a/embassy-traits/src/lib.rs b/embassy-traits/src/lib.rs
index 65fb95bd4..a5342b77e 100644
--- a/embassy-traits/src/lib.rs
+++ b/embassy-traits/src/lib.rs
@@ -2,6 +2,7 @@
2#![feature(generic_associated_types)] 2#![feature(generic_associated_types)]
3#![feature(type_alias_impl_trait)] 3#![feature(type_alias_impl_trait)]
4 4
5pub mod adapter;
5pub mod delay; 6pub mod delay;
6pub mod flash; 7pub mod flash;
7pub mod gpio; 8pub mod gpio;
diff --git a/examples/stm32l4/src/bin/i2c_blocking_async.rs b/examples/stm32l4/src/bin/i2c_blocking_async.rs
new file mode 100644
index 000000000..0339ed4d3
--- /dev/null
+++ b/examples/stm32l4/src/bin/i2c_blocking_async.rs
@@ -0,0 +1,29 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5#[path = "../example_common.rs"]
6mod example_common;
7
8use embassy::executor::Spawner;
9use embassy_stm32::dma::NoDma;
10use embassy_stm32::i2c::I2c;
11use embassy_stm32::interrupt;
12use embassy_stm32::time::Hertz;
13use embassy_stm32::Peripherals;
14use embassy_traits::{adapter::BlockingAsync, i2c::I2c as _};
15use example_common::{info, unwrap};
16
17const ADDRESS: u8 = 0x5F;
18const WHOAMI: u8 = 0x0F;
19
20#[embassy::main]
21async fn main(_spawner: Spawner, p: Peripherals) -> ! {
22 let irq = interrupt::take!(I2C2_EV);
23 let i2c = I2c::new(p.I2C2, p.PB10, p.PB11, irq, NoDma, NoDma, Hertz(100_000));
24 let mut i2c = BlockingAsync::new(i2c);
25
26 let mut data = [0u8; 1];
27 unwrap!(i2c.write_read(ADDRESS, &[WHOAMI], &mut data).await);
28 info!("Whoami: {}", data[0]);
29}
diff --git a/examples/stm32l4/src/bin/spi_blocking_async.rs b/examples/stm32l4/src/bin/spi_blocking_async.rs
new file mode 100644
index 000000000..f092706d4
--- /dev/null
+++ b/examples/stm32l4/src/bin/spi_blocking_async.rs
@@ -0,0 +1,57 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5#[path = "../example_common.rs"]
6mod example_common;
7
8use embassy::executor::Spawner;
9use embassy_stm32::dma::NoDma;
10use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed};
11use embassy_stm32::spi::{Config, Spi};
12use embassy_stm32::time::Hertz;
13use embassy_stm32::Peripherals;
14use embassy_traits::{adapter::BlockingAsync, spi::FullDuplex};
15use embedded_hal::digital::v2::{InputPin, OutputPin};
16use example_common::*;
17
18#[embassy::main]
19async fn main(_spawner: Spawner, p: Peripherals) {
20 info!("Hello World!");
21
22 let spi = Spi::new(
23 p.SPI3,
24 p.PC10,
25 p.PC12,
26 p.PC11,
27 NoDma,
28 NoDma,
29 Hertz(1_000_000),
30 Config::default(),
31 );
32
33 let mut spi = BlockingAsync::new(spi);
34
35 // These are the pins for the Inventek eS-Wifi SPI Wifi Adapter.
36
37 let _boot = Output::new(p.PB12, Level::Low, Speed::VeryHigh);
38 let _wake = Output::new(p.PB13, Level::Low, Speed::VeryHigh);
39 let mut reset = Output::new(p.PE8, Level::Low, Speed::VeryHigh);
40 let mut cs = Output::new(p.PE0, Level::High, Speed::VeryHigh);
41 let ready = Input::new(p.PE1, Pull::Up);
42
43 cortex_m::asm::delay(100_000);
44 unwrap!(reset.set_high());
45 cortex_m::asm::delay(100_000);
46
47 while unwrap!(ready.is_low()) {
48 info!("waiting for ready");
49 }
50
51 let write = [0x0A; 10];
52 let mut read = [0; 10];
53 unwrap!(cs.set_low());
54 spi.read_write(&mut read, &write).await.ok();
55 unwrap!(cs.set_high());
56 info!("xfer {=[u8]:x}", read);
57}
diff --git a/examples/stm32l4/src/bin/usart_blocking_async.rs b/examples/stm32l4/src/bin/usart_blocking_async.rs
new file mode 100644
index 000000000..679d4e0da
--- /dev/null
+++ b/examples/stm32l4/src/bin/usart_blocking_async.rs
@@ -0,0 +1,32 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5#[path = "../example_common.rs"]
6mod example_common;
7
8use embassy::executor::Spawner;
9use embassy::traits::{
10 adapter::BlockingAsync,
11 uart::{Read, Write},
12};
13use embassy_stm32::dma::NoDma;
14use embassy_stm32::usart::{Config, Uart};
15use embassy_stm32::Peripherals;
16use example_common::*;
17
18#[embassy::main]
19async fn main(_spawner: Spawner, p: Peripherals) {
20 let config = Config::default();
21 let usart = Uart::new(p.UART4, p.PA1, p.PA0, NoDma, NoDma, config);
22 let mut usart = BlockingAsync::new(usart);
23
24 unwrap!(usart.write(b"Hello Embassy World!\r\n").await);
25 info!("wrote Hello, starting echo");
26
27 let mut buf = [0u8; 1];
28 loop {
29 unwrap!(usart.read(&mut buf).await);
30 unwrap!(usart.write(&buf).await);
31 }
32}