aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-hal-common/src/ring_buffer.rs45
-rw-r--r--embassy-stm32/Cargo.toml2
-rw-r--r--embassy-stm32/src/usart/mod.rs14
-rw-r--r--embassy-stm32/src/usart/v2.rs226
-rw-r--r--examples/stm32l0/Cargo.toml1
-rw-r--r--examples/stm32l0/src/bin/usart_irq.rs51
m---------stm32-data0
7 files changed, 324 insertions, 15 deletions
diff --git a/embassy-hal-common/src/ring_buffer.rs b/embassy-hal-common/src/ring_buffer.rs
index 18795787f..6829f62f5 100644
--- a/embassy-hal-common/src/ring_buffer.rs
+++ b/embassy-hal-common/src/ring_buffer.rs
@@ -67,6 +67,14 @@ impl<'a> RingBuffer<'a> {
67 self.empty = self.start == self.end; 67 self.empty = self.start == self.end;
68 } 68 }
69 69
70 pub fn is_full(&self) -> bool {
71 self.start == self.end && !self.empty
72 }
73
74 pub fn is_empty(&self) -> bool {
75 self.empty
76 }
77
70 pub fn clear(&mut self) { 78 pub fn clear(&mut self) {
71 self.start = 0; 79 self.start = 0;
72 self.end = 0; 80 self.end = 0;
@@ -82,3 +90,40 @@ impl<'a> RingBuffer<'a> {
82 } 90 }
83 } 91 }
84} 92}
93
94#[cfg(test)]
95mod tests {
96 use super::*;
97
98 #[test]
99 fn push_pop() {
100 let mut b = [0; 4];
101 let mut rb = RingBuffer::new(&mut b);
102 let buf = rb.push_buf();
103 assert_eq!(4, buf.len());
104 buf[0] = 1;
105 buf[1] = 2;
106 buf[2] = 3;
107 buf[3] = 4;
108 rb.push(4);
109
110 let buf = rb.pop_buf();
111 assert_eq!(4, buf.len());
112 assert_eq!(1, buf[0]);
113 rb.pop(1);
114
115 let buf = rb.pop_buf();
116 assert_eq!(3, buf.len());
117 assert_eq!(2, buf[0]);
118 rb.pop(1);
119
120 let buf = rb.pop_buf();
121 assert_eq!(2, buf.len());
122 assert_eq!(3, buf[0]);
123 rb.pop(1);
124
125 let buf = rb.pop_buf();
126 assert_eq!(1, buf.len());
127 assert_eq!(4, buf[0]);
128 }
129}
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml
index 9b9db0f0c..fd121f6db 100644
--- a/embassy-stm32/Cargo.toml
+++ b/embassy-stm32/Cargo.toml
@@ -23,7 +23,7 @@ sdio-host = { version = "0.5.0" }
23embedded-sdmmc = { git = "https://github.com/thalesfragoso/embedded-sdmmc-rs", branch = "async", optional = true } 23embedded-sdmmc = { git = "https://github.com/thalesfragoso/embedded-sdmmc-rs", branch = "async", optional = true }
24critical-section = "0.2.1" 24critical-section = "0.2.1"
25bare-metal = "1.0.0" 25bare-metal = "1.0.0"
26atomic-polyfill = "0.1.2" 26atomic-polyfill = "0.1.3"
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 }
29 29
diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs
index 9df00d3a8..c1cdd8d73 100644
--- a/embassy-stm32/src/usart/mod.rs
+++ b/embassy-stm32/src/usart/mod.rs
@@ -8,6 +8,7 @@ pub use _version::*;
8 8
9use crate::gpio::Pin; 9use crate::gpio::Pin;
10use crate::rcc::RccPeripheral; 10use crate::rcc::RccPeripheral;
11use embassy::interrupt::Interrupt;
11 12
12#[derive(Clone, Copy, PartialEq, Eq, Debug)] 13#[derive(Clone, Copy, PartialEq, Eq, Debug)]
13pub enum DataBits { 14pub enum DataBits {
@@ -100,7 +101,9 @@ pub(crate) mod sealed {
100 } 101 }
101} 102}
102 103
103pub trait Instance: sealed::Instance + RccPeripheral {} 104pub trait Instance: sealed::Instance + RccPeripheral {
105 type Interrupt: Interrupt;
106}
104pub trait RxPin<T: Instance>: sealed::RxPin<T> {} 107pub trait RxPin<T: Instance>: sealed::RxPin<T> {}
105pub trait TxPin<T: Instance>: sealed::TxPin<T> {} 108pub trait TxPin<T: Instance>: sealed::TxPin<T> {}
106pub trait CtsPin<T: Instance>: sealed::CtsPin<T> {} 109pub trait CtsPin<T: Instance>: sealed::CtsPin<T> {}
@@ -109,15 +112,18 @@ pub trait CkPin<T: Instance>: sealed::CkPin<T> {}
109pub trait RxDma<T: Instance>: sealed::RxDma<T> + dma::Channel {} 112pub trait RxDma<T: Instance>: sealed::RxDma<T> + dma::Channel {}
110pub trait TxDma<T: Instance>: sealed::TxDma<T> + dma::Channel {} 113pub trait TxDma<T: Instance>: sealed::TxDma<T> + dma::Channel {}
111 114
112crate::pac::peripherals!( 115crate::pac::interrupts!(
113 (usart, $inst:ident) => { 116 ($inst:ident, usart, $block:ident, $signal_name:ident, $irq:ident) => {
114 impl sealed::Instance for peripherals::$inst { 117 impl sealed::Instance for peripherals::$inst {
115 fn regs(&self) -> crate::pac::usart::Usart { 118 fn regs(&self) -> crate::pac::usart::Usart {
116 crate::pac::$inst 119 crate::pac::$inst
117 } 120 }
118 } 121 }
119 122
120 impl Instance for peripherals::$inst {} 123 impl Instance for peripherals::$inst {
124 type Interrupt = crate::interrupt::$irq;
125 }
126
121 }; 127 };
122); 128);
123 129
diff --git a/embassy-stm32/src/usart/v2.rs b/embassy-stm32/src/usart/v2.rs
index 50996dbbf..92c0cbc2e 100644
--- a/embassy-stm32/src/usart/v2.rs
+++ b/embassy-stm32/src/usart/v2.rs
@@ -1,6 +1,12 @@
1use atomic_polyfill::{compiler_fence, Ordering};
1use core::future::Future; 2use core::future::Future;
2use core::marker::PhantomData; 3use core::marker::PhantomData;
3use embassy::util::Unborrow; 4use core::pin::Pin;
5use core::task::Context;
6use core::task::Poll;
7use embassy::util::{Unborrow, WakerRegistration};
8use embassy_hal_common::peripheral::{PeripheralMutex, PeripheralState, StateStorage};
9use embassy_hal_common::ring_buffer::RingBuffer;
4use embassy_hal_common::unborrow; 10use embassy_hal_common::unborrow;
5use futures::TryFutureExt; 11use futures::TryFutureExt;
6 12
@@ -12,7 +18,6 @@ pub struct Uart<'d, T: Instance, TxDma = NoDma, RxDma = NoDma> {
12 inner: T, 18 inner: T,
13 phantom: PhantomData<&'d mut T>, 19 phantom: PhantomData<&'d mut T>,
14 tx_dma: TxDma, 20 tx_dma: TxDma,
15 #[allow(dead_code)]
16 rx_dma: RxDma, 21 rx_dma: RxDma,
17} 22}
18 23
@@ -153,25 +158,226 @@ impl<'d, T: Instance, RxDma> embedded_hal::blocking::serial::Write<u8>
153} 158}
154 159
155// rustfmt::skip because intellij removes the 'where' claus on the associated type. 160// rustfmt::skip because intellij removes the 'where' claus on the associated type.
156#[rustfmt::skip]
157impl<'d, T: Instance, TxDma, RxDma> embassy_traits::uart::Write for Uart<'d, T, TxDma, RxDma> 161impl<'d, T: Instance, TxDma, RxDma> embassy_traits::uart::Write for Uart<'d, T, TxDma, RxDma>
158 where TxDma: crate::usart::TxDma<T> 162where
163 TxDma: crate::usart::TxDma<T>,
159{ 164{
160 type WriteFuture<'a> where Self: 'a = impl Future<Output = Result<(), embassy_traits::uart::Error>> + 'a; 165 // rustfmt::skip because rustfmt removes the 'where' claus on the associated type.
166 #[rustfmt::skip]
167 type WriteFuture<'a> where Self: 'a = impl Future<Output = Result<(), embassy_traits::uart::Error>> +'a;
161 168
162 fn write<'a>(&'a mut self, buf: &'a [u8]) -> Self::WriteFuture<'a> { 169 fn write<'a>(&'a mut self, buf: &'a [u8]) -> Self::WriteFuture<'a> {
163 self.write_dma(buf).map_err(|_| embassy_traits::uart::Error::Other) 170 self.write_dma(buf)
171 .map_err(|_| embassy_traits::uart::Error::Other)
164 } 172 }
165} 173}
166 174
167// rustfmt::skip because intellij removes the 'where' claus on the associated type.
168#[rustfmt::skip]
169impl<'d, T: Instance, TxDma, RxDma> embassy_traits::uart::Read for Uart<'d, T, TxDma, RxDma> 175impl<'d, T: Instance, TxDma, RxDma> embassy_traits::uart::Read for Uart<'d, T, TxDma, RxDma>
170 where RxDma: crate::usart::RxDma<T> 176where
177 RxDma: crate::usart::RxDma<T>,
171{ 178{
179 // rustfmt::skip because rustfmt removes the 'where' claus on the associated type.
180 #[rustfmt::skip]
172 type ReadFuture<'a> where Self: 'a = impl Future<Output = Result<(), embassy_traits::uart::Error>> + 'a; 181 type ReadFuture<'a> where Self: 'a = impl Future<Output = Result<(), embassy_traits::uart::Error>> + 'a;
173 182
174 fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReadFuture<'a> { 183 fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReadFuture<'a> {
175 self.read_dma(buf).map_err(|_| embassy_traits::uart::Error::Other) 184 self.read_dma(buf)
185 .map_err(|_| embassy_traits::uart::Error::Other)
186 }
187}
188
189pub struct State<'d, T: Instance>(StateStorage<StateInner<'d, T>>);
190impl<'d, T: Instance> State<'d, T> {
191 pub fn new() -> Self {
192 Self(StateStorage::new())
193 }
194}
195
196pub struct StateInner<'d, T: Instance> {
197 uart: Uart<'d, T, NoDma, NoDma>,
198 phantom: PhantomData<&'d mut T>,
199
200 rx_waker: WakerRegistration,
201 rx: RingBuffer<'d>,
202
203 tx_waker: WakerRegistration,
204 tx: RingBuffer<'d>,
205}
206
207unsafe impl<'d, T: Instance> Send for StateInner<'d, T> {}
208unsafe impl<'d, T: Instance> Sync for StateInner<'d, T> {}
209
210pub struct BufferedUart<'d, T: Instance> {
211 inner: PeripheralMutex<'d, StateInner<'d, T>>,
212}
213
214impl<'d, T: Instance> Unpin for BufferedUart<'d, T> {}
215
216impl<'d, T: Instance> BufferedUart<'d, T> {
217 pub unsafe fn new(
218 state: &'d mut State<'d, T>,
219 uart: Uart<'d, T, NoDma, NoDma>,
220 irq: impl Unborrow<Target = T::Interrupt> + 'd,
221 tx_buffer: &'d mut [u8],
222 rx_buffer: &'d mut [u8],
223 ) -> BufferedUart<'d, T> {
224 unborrow!(irq);
225
226 let r = uart.inner.regs();
227 r.cr1().modify(|w| {
228 w.set_rxneie(true);
229 w.set_idleie(true);
230 });
231
232 Self {
233 inner: PeripheralMutex::new_unchecked(irq, &mut state.0, move || StateInner {
234 uart,
235 phantom: PhantomData,
236 tx: RingBuffer::new(tx_buffer),
237 tx_waker: WakerRegistration::new(),
238
239 rx: RingBuffer::new(rx_buffer),
240 rx_waker: WakerRegistration::new(),
241 }),
242 }
243 }
244}
245
246impl<'d, T: Instance> StateInner<'d, T>
247where
248 Self: 'd,
249{
250 fn on_rx(&mut self) {
251 let r = self.uart.inner.regs();
252 unsafe {
253 let sr = r.isr().read();
254 if sr.pe() {
255 r.icr().write(|w| {
256 w.set_pe(true);
257 });
258 trace!("Parity error");
259 } else if sr.fe() {
260 r.icr().write(|w| {
261 w.set_fe(true);
262 });
263 trace!("Framing error");
264 } else if sr.nf() {
265 r.icr().write(|w| {
266 w.set_nf(true);
267 });
268 trace!("Noise error");
269 } else if sr.ore() {
270 r.icr().write(|w| {
271 w.set_ore(true);
272 });
273 trace!("Overrun error");
274 } else if sr.rxne() {
275 let buf = self.rx.push_buf();
276 if buf.is_empty() {
277 self.rx_waker.wake();
278 } else {
279 buf[0] = r.rdr().read().0 as u8;
280 self.rx.push(1);
281 }
282 } else if sr.idle() {
283 r.icr().write(|w| {
284 w.set_idle(true);
285 });
286 self.rx_waker.wake();
287 };
288 }
289 }
290
291 fn on_tx(&mut self) {
292 let r = self.uart.inner.regs();
293 unsafe {
294 if r.isr().read().txe() {
295 let buf = self.tx.pop_buf();
296 if !buf.is_empty() {
297 r.cr1().modify(|w| {
298 w.set_txeie(true);
299 });
300 r.tdr().write_value(regs::Dr(buf[0].into()));
301 self.tx.pop(1);
302 self.tx_waker.wake();
303 } else {
304 // Disable interrupt until we have something to transmit again
305 r.cr1().modify(|w| {
306 w.set_txeie(false);
307 });
308 }
309 }
310 }
311 }
312}
313
314impl<'d, T: Instance> PeripheralState for StateInner<'d, T>
315where
316 Self: 'd,
317{
318 type Interrupt = T::Interrupt;
319 fn on_interrupt(&mut self) {
320 self.on_rx();
321 self.on_tx();
322 }
323}
324
325impl<'d, T: Instance> embassy::io::AsyncBufRead for BufferedUart<'d, T> {
326 fn poll_fill_buf(
327 mut self: Pin<&mut Self>,
328 cx: &mut Context<'_>,
329 ) -> Poll<Result<&[u8], embassy::io::Error>> {
330 self.inner.with(|state| {
331 compiler_fence(Ordering::SeqCst);
332
333 // We have data ready in buffer? Return it.
334 let buf = state.rx.pop_buf();
335 if !buf.is_empty() {
336 let buf: &[u8] = buf;
337 // Safety: buffer lives as long as uart
338 let buf: &[u8] = unsafe { core::mem::transmute(buf) };
339 return Poll::Ready(Ok(buf));
340 }
341
342 state.rx_waker.register(cx.waker());
343 Poll::<Result<&[u8], embassy::io::Error>>::Pending
344 })
345 }
346 fn consume(mut self: Pin<&mut Self>, amt: usize) {
347 let signal = self.inner.with(|state| {
348 let full = state.rx.is_full();
349 state.rx.pop(amt);
350 full
351 });
352 if signal {
353 self.inner.pend();
354 }
355 }
356}
357
358impl<'d, T: Instance> embassy::io::AsyncWrite for BufferedUart<'d, T> {
359 fn poll_write(
360 mut self: Pin<&mut Self>,
361 cx: &mut Context<'_>,
362 buf: &[u8],
363 ) -> Poll<Result<usize, embassy::io::Error>> {
364 let (poll, empty) = self.inner.with(|state| {
365 let empty = state.tx.is_empty();
366 let tx_buf = state.tx.push_buf();
367 if tx_buf.is_empty() {
368 state.tx_waker.register(cx.waker());
369 return (Poll::Pending, empty);
370 }
371
372 let n = core::cmp::min(tx_buf.len(), buf.len());
373 tx_buf[..n].copy_from_slice(&buf[..n]);
374 state.tx.push(n);
375
376 (Poll::Ready(Ok(n)), empty)
377 });
378 if empty {
379 self.inner.pend();
380 }
381 poll
176 } 382 }
177} 383}
diff --git a/examples/stm32l0/Cargo.toml b/examples/stm32l0/Cargo.toml
index 6c594df66..9b3166154 100644
--- a/examples/stm32l0/Cargo.toml
+++ b/examples/stm32l0/Cargo.toml
@@ -21,6 +21,7 @@ embassy = { version = "0.1.0", path = "../../embassy", features = ["defmt", "def
21embassy-traits = { version = "0.1.0", path = "../../embassy-traits", features = ["defmt"] } 21embassy-traits = { version = "0.1.0", path = "../../embassy-traits", features = ["defmt"] }
22embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "defmt-trace", "stm32l072cz", "time-driver-tim3"] } 22embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "defmt-trace", "stm32l072cz", "time-driver-tim3"] }
23embassy-hal-common = {version = "0.1.0", path = "../../embassy-hal-common" } 23embassy-hal-common = {version = "0.1.0", path = "../../embassy-hal-common" }
24embassy-macros = { path = "../../embassy-macros" }
24 25
25defmt = "0.2.0" 26defmt = "0.2.0"
26defmt-rtt = "0.2.0" 27defmt-rtt = "0.2.0"
diff --git a/examples/stm32l0/src/bin/usart_irq.rs b/examples/stm32l0/src/bin/usart_irq.rs
new file mode 100644
index 000000000..5c79d0671
--- /dev/null
+++ b/examples/stm32l0/src/bin/usart_irq.rs
@@ -0,0 +1,51 @@
1#![no_std]
2#![no_main]
3#![feature(trait_alias)]
4#![feature(type_alias_impl_trait)]
5#![allow(incomplete_features)]
6
7#[path = "../example_common.rs"]
8mod example_common;
9
10use example_common::*;
11
12use defmt::panic;
13use embassy::executor::Spawner;
14use embassy::io::{AsyncBufReadExt, AsyncWriteExt};
15use embassy_stm32::dma::NoDma;
16use embassy_stm32::interrupt;
17use embassy_stm32::usart::{BufferedUart, Config, State, Uart};
18use embassy_stm32::{rcc, Peripherals};
19
20#[embassy::main]
21async fn main(_spawner: Spawner, mut p: Peripherals) {
22 let mut rcc = rcc::Rcc::new(p.RCC);
23 rcc.enable_debug_wfe(&mut p.DBGMCU, true);
24
25 static mut TX_BUFFER: [u8; 8] = [0; 8];
26 static mut RX_BUFFER: [u8; 256] = [0; 256];
27
28 let mut config = Config::default();
29 config.baudrate = 9600;
30
31 let usart = Uart::new(p.USART1, p.PA10, p.PA9, NoDma, NoDma, config);
32 let mut state = State::new();
33 let mut usart = unsafe {
34 BufferedUart::new(
35 &mut state,
36 usart,
37 interrupt::take!(USART1),
38 &mut TX_BUFFER,
39 &mut RX_BUFFER,
40 )
41 };
42
43 usart.write_all(b"Hello Embassy World!\r\n").await.unwrap();
44 info!("wrote Hello, starting echo");
45
46 let mut buf = [0; 4];
47 loop {
48 usart.read_exact(&mut buf[..]).await.unwrap();
49 usart.write_all(&buf[..]).await.unwrap();
50 }
51}
diff --git a/stm32-data b/stm32-data
Subproject af0611ff9b29f2c0ab675a4f0e51d8241a4097f Subproject 79ab92a38d1cbb47dda2f6f8556fe1abc9a14f3