aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-executor/src/raw/mod.rs179
-rw-r--r--embassy-executor/src/raw/timer_queue.rs14
-rw-r--r--embassy-executor/src/raw/util.rs29
-rw-r--r--embassy-executor/src/spawner.rs12
-rw-r--r--embassy-rp/src/dma.rs1
-rw-r--r--embassy-rp/src/spi.rs45
-rw-r--r--embassy-rp/src/uart/buffered.rs74
-rw-r--r--embassy-stm32/Cargo.toml4
-rw-r--r--embassy-stm32/build.rs7
-rw-r--r--embassy-stm32/src/adc/sample_time.rs13
-rw-r--r--embassy-stm32/src/lib.rs3
-rw-r--r--embassy-stm32/src/qspi/enums.rs294
-rw-r--r--embassy-stm32/src/qspi/mod.rs338
-rw-r--r--embassy-stm32/src/usart/buffered.rs99
-rw-r--r--embassy-sync/src/pipe.rs71
-rw-r--r--embassy-usb/src/builder.rs8
-rw-r--r--embassy-usb/src/class/hid.rs3
-rw-r--r--embassy-usb/src/lib.rs37
-rw-r--r--embassy-usb/src/msos.rs5
-rw-r--r--tests/rp/src/bin/spi_async.rs64
20 files changed, 1153 insertions, 147 deletions
diff --git a/embassy-executor/src/raw/mod.rs b/embassy-executor/src/raw/mod.rs
index 42bd82262..15ff18fc8 100644
--- a/embassy-executor/src/raw/mod.rs
+++ b/embassy-executor/src/raw/mod.rs
@@ -13,11 +13,12 @@ mod timer_queue;
13pub(crate) mod util; 13pub(crate) mod util;
14mod waker; 14mod waker;
15 15
16use core::cell::Cell;
17use core::future::Future; 16use core::future::Future;
17use core::marker::PhantomData;
18use core::mem; 18use core::mem;
19use core::pin::Pin; 19use core::pin::Pin;
20use core::ptr::NonNull; 20use core::ptr::NonNull;
21use core::sync::atomic::AtomicPtr;
21use core::task::{Context, Poll}; 22use core::task::{Context, Poll};
22 23
23use atomic_polyfill::{AtomicU32, Ordering}; 24use atomic_polyfill::{AtomicU32, Ordering};
@@ -30,7 +31,7 @@ use embassy_time::Instant;
30use rtos_trace::trace; 31use rtos_trace::trace;
31 32
32use self::run_queue::{RunQueue, RunQueueItem}; 33use self::run_queue::{RunQueue, RunQueueItem};
33use self::util::UninitCell; 34use self::util::{SyncUnsafeCell, UninitCell};
34pub use self::waker::task_from_waker; 35pub use self::waker::task_from_waker;
35use super::SpawnToken; 36use super::SpawnToken;
36 37
@@ -46,11 +47,11 @@ pub(crate) const STATE_TIMER_QUEUED: u32 = 1 << 2;
46pub(crate) struct TaskHeader { 47pub(crate) struct TaskHeader {
47 pub(crate) state: AtomicU32, 48 pub(crate) state: AtomicU32,
48 pub(crate) run_queue_item: RunQueueItem, 49 pub(crate) run_queue_item: RunQueueItem,
49 pub(crate) executor: Cell<Option<&'static Executor>>, 50 pub(crate) executor: SyncUnsafeCell<Option<&'static SyncExecutor>>,
50 poll_fn: Cell<Option<unsafe fn(TaskRef)>>, 51 poll_fn: SyncUnsafeCell<Option<unsafe fn(TaskRef)>>,
51 52
52 #[cfg(feature = "integrated-timers")] 53 #[cfg(feature = "integrated-timers")]
53 pub(crate) expires_at: Cell<Instant>, 54 pub(crate) expires_at: SyncUnsafeCell<Instant>,
54 #[cfg(feature = "integrated-timers")] 55 #[cfg(feature = "integrated-timers")]
55 pub(crate) timer_queue_item: timer_queue::TimerQueueItem, 56 pub(crate) timer_queue_item: timer_queue::TimerQueueItem,
56} 57}
@@ -61,6 +62,9 @@ pub struct TaskRef {
61 ptr: NonNull<TaskHeader>, 62 ptr: NonNull<TaskHeader>,
62} 63}
63 64
65unsafe impl Send for TaskRef where &'static TaskHeader: Send {}
66unsafe impl Sync for TaskRef where &'static TaskHeader: Sync {}
67
64impl TaskRef { 68impl TaskRef {
65 fn new<F: Future + 'static>(task: &'static TaskStorage<F>) -> Self { 69 fn new<F: Future + 'static>(task: &'static TaskStorage<F>) -> Self {
66 Self { 70 Self {
@@ -115,12 +119,12 @@ impl<F: Future + 'static> TaskStorage<F> {
115 raw: TaskHeader { 119 raw: TaskHeader {
116 state: AtomicU32::new(0), 120 state: AtomicU32::new(0),
117 run_queue_item: RunQueueItem::new(), 121 run_queue_item: RunQueueItem::new(),
118 executor: Cell::new(None), 122 executor: SyncUnsafeCell::new(None),
119 // Note: this is lazily initialized so that a static `TaskStorage` will go in `.bss` 123 // Note: this is lazily initialized so that a static `TaskStorage` will go in `.bss`
120 poll_fn: Cell::new(None), 124 poll_fn: SyncUnsafeCell::new(None),
121 125
122 #[cfg(feature = "integrated-timers")] 126 #[cfg(feature = "integrated-timers")]
123 expires_at: Cell::new(Instant::from_ticks(0)), 127 expires_at: SyncUnsafeCell::new(Instant::from_ticks(0)),
124 #[cfg(feature = "integrated-timers")] 128 #[cfg(feature = "integrated-timers")]
125 timer_queue_item: timer_queue::TimerQueueItem::new(), 129 timer_queue_item: timer_queue::TimerQueueItem::new(),
126 }, 130 },
@@ -170,9 +174,15 @@ impl<F: Future + 'static> TaskStorage<F> {
170 // it's a noop for our waker. 174 // it's a noop for our waker.
171 mem::forget(waker); 175 mem::forget(waker);
172 } 176 }
173}
174 177
175unsafe impl<F: Future + 'static> Sync for TaskStorage<F> {} 178 #[doc(hidden)]
179 #[allow(dead_code)]
180 fn _assert_sync(self) {
181 fn assert_sync<T: Sync>(_: T) {}
182
183 assert_sync(self)
184 }
185}
176 186
177struct AvailableTask<F: Future + 'static> { 187struct AvailableTask<F: Future + 'static> {
178 task: &'static TaskStorage<F>, 188 task: &'static TaskStorage<F>,
@@ -279,29 +289,10 @@ impl<F: Future + 'static, const N: usize> TaskPool<F, N> {
279 } 289 }
280} 290}
281 291
282/// Raw executor. 292pub(crate) struct SyncExecutor {
283///
284/// This is the core of the Embassy executor. It is low-level, requiring manual
285/// handling of wakeups and task polling. If you can, prefer using one of the
286/// [higher level executors](crate::Executor).
287///
288/// The raw executor leaves it up to you to handle wakeups and scheduling:
289///
290/// - To get the executor to do work, call `poll()`. This will poll all queued tasks (all tasks
291/// that "want to run").
292/// - You must supply a `signal_fn`. The executor will call it to notify you it has work
293/// to do. You must arrange for `poll()` to be called as soon as possible.
294///
295/// `signal_fn` can be called from *any* context: any thread, any interrupt priority
296/// level, etc. It may be called synchronously from any `Executor` method call as well.
297/// You must deal with this correctly.
298///
299/// In particular, you must NOT call `poll` directly from `signal_fn`, as this violates
300/// the requirement for `poll` to not be called reentrantly.
301pub struct Executor {
302 run_queue: RunQueue, 293 run_queue: RunQueue,
303 signal_fn: fn(*mut ()), 294 signal_fn: fn(*mut ()),
304 signal_ctx: *mut (), 295 signal_ctx: AtomicPtr<()>,
305 296
306 #[cfg(feature = "integrated-timers")] 297 #[cfg(feature = "integrated-timers")]
307 pub(crate) timer_queue: timer_queue::TimerQueue, 298 pub(crate) timer_queue: timer_queue::TimerQueue,
@@ -309,14 +300,8 @@ pub struct Executor {
309 alarm: AlarmHandle, 300 alarm: AlarmHandle,
310} 301}
311 302
312impl Executor { 303impl SyncExecutor {
313 /// Create a new executor. 304 pub(crate) fn new(signal_fn: fn(*mut ()), signal_ctx: *mut ()) -> Self {
314 ///
315 /// When the executor has work to do, it will call `signal_fn` with
316 /// `signal_ctx` as argument.
317 ///
318 /// See [`Executor`] docs for details on `signal_fn`.
319 pub fn new(signal_fn: fn(*mut ()), signal_ctx: *mut ()) -> Self {
320 #[cfg(feature = "integrated-timers")] 305 #[cfg(feature = "integrated-timers")]
321 let alarm = unsafe { unwrap!(driver::allocate_alarm()) }; 306 let alarm = unsafe { unwrap!(driver::allocate_alarm()) };
322 #[cfg(feature = "integrated-timers")] 307 #[cfg(feature = "integrated-timers")]
@@ -325,7 +310,7 @@ impl Executor {
325 Self { 310 Self {
326 run_queue: RunQueue::new(), 311 run_queue: RunQueue::new(),
327 signal_fn, 312 signal_fn,
328 signal_ctx, 313 signal_ctx: AtomicPtr::new(signal_ctx),
329 314
330 #[cfg(feature = "integrated-timers")] 315 #[cfg(feature = "integrated-timers")]
331 timer_queue: timer_queue::TimerQueue::new(), 316 timer_queue: timer_queue::TimerQueue::new(),
@@ -346,19 +331,10 @@ impl Executor {
346 trace::task_ready_begin(task.as_ptr() as u32); 331 trace::task_ready_begin(task.as_ptr() as u32);
347 332
348 if self.run_queue.enqueue(cs, task) { 333 if self.run_queue.enqueue(cs, task) {
349 (self.signal_fn)(self.signal_ctx) 334 (self.signal_fn)(self.signal_ctx.load(Ordering::Relaxed))
350 } 335 }
351 } 336 }
352 337
353 /// Spawn a task in this executor.
354 ///
355 /// # Safety
356 ///
357 /// `task` must be a valid pointer to an initialized but not-already-spawned task.
358 ///
359 /// It is OK to use `unsafe` to call this from a thread that's not the executor thread.
360 /// In this case, the task's Future must be Send. This is because this is effectively
361 /// sending the task to the executor thread.
362 pub(super) unsafe fn spawn(&'static self, task: TaskRef) { 338 pub(super) unsafe fn spawn(&'static self, task: TaskRef) {
363 task.header().executor.set(Some(self)); 339 task.header().executor.set(Some(self));
364 340
@@ -370,24 +346,11 @@ impl Executor {
370 }) 346 })
371 } 347 }
372 348
373 /// Poll all queued tasks in this executor.
374 ///
375 /// This loops over all tasks that are queued to be polled (i.e. they're
376 /// freshly spawned or they've been woken). Other tasks are not polled.
377 ///
378 /// You must call `poll` after receiving a call to `signal_fn`. It is OK
379 /// to call `poll` even when not requested by `signal_fn`, but it wastes
380 /// energy.
381 ///
382 /// # Safety 349 /// # Safety
383 /// 350 ///
384 /// You must NOT call `poll` reentrantly on the same executor. 351 /// Same as [`Executor::poll`], plus you must only call this on the thread this executor was created.
385 /// 352 pub(crate) unsafe fn poll(&'static self) {
386 /// In particular, note that `poll` may call `signal_fn` synchronously. Therefore, you 353 #[allow(clippy::never_loop)]
387 /// must NOT directly call `poll()` from your `signal_fn`. Instead, `signal_fn` has to
388 /// somehow schedule for `poll()` to be called later, at a time you know for sure there's
389 /// no `poll()` already running.
390 pub unsafe fn poll(&'static self) {
391 loop { 354 loop {
392 #[cfg(feature = "integrated-timers")] 355 #[cfg(feature = "integrated-timers")]
393 self.timer_queue.dequeue_expired(Instant::now(), |task| wake_task(task)); 356 self.timer_queue.dequeue_expired(Instant::now(), |task| wake_task(task));
@@ -441,6 +404,84 @@ impl Executor {
441 #[cfg(feature = "rtos-trace")] 404 #[cfg(feature = "rtos-trace")]
442 trace::system_idle(); 405 trace::system_idle();
443 } 406 }
407}
408
409/// Raw executor.
410///
411/// This is the core of the Embassy executor. It is low-level, requiring manual
412/// handling of wakeups and task polling. If you can, prefer using one of the
413/// [higher level executors](crate::Executor).
414///
415/// The raw executor leaves it up to you to handle wakeups and scheduling:
416///
417/// - To get the executor to do work, call `poll()`. This will poll all queued tasks (all tasks
418/// that "want to run").
419/// - You must supply a `signal_fn`. The executor will call it to notify you it has work
420/// to do. You must arrange for `poll()` to be called as soon as possible.
421///
422/// `signal_fn` can be called from *any* context: any thread, any interrupt priority
423/// level, etc. It may be called synchronously from any `Executor` method call as well.
424/// You must deal with this correctly.
425///
426/// In particular, you must NOT call `poll` directly from `signal_fn`, as this violates
427/// the requirement for `poll` to not be called reentrantly.
428#[repr(transparent)]
429pub struct Executor {
430 pub(crate) inner: SyncExecutor,
431
432 _not_sync: PhantomData<*mut ()>,
433}
434
435impl Executor {
436 pub(crate) unsafe fn wrap(inner: &SyncExecutor) -> &Self {
437 mem::transmute(inner)
438 }
439 /// Create a new executor.
440 ///
441 /// When the executor has work to do, it will call `signal_fn` with
442 /// `signal_ctx` as argument.
443 ///
444 /// See [`Executor`] docs for details on `signal_fn`.
445 pub fn new(signal_fn: fn(*mut ()), signal_ctx: *mut ()) -> Self {
446 Self {
447 inner: SyncExecutor::new(signal_fn, signal_ctx),
448 _not_sync: PhantomData,
449 }
450 }
451
452 /// Spawn a task in this executor.
453 ///
454 /// # Safety
455 ///
456 /// `task` must be a valid pointer to an initialized but not-already-spawned task.
457 ///
458 /// It is OK to use `unsafe` to call this from a thread that's not the executor thread.
459 /// In this case, the task's Future must be Send. This is because this is effectively
460 /// sending the task to the executor thread.
461 pub(super) unsafe fn spawn(&'static self, task: TaskRef) {
462 self.inner.spawn(task)
463 }
464
465 /// Poll all queued tasks in this executor.
466 ///
467 /// This loops over all tasks that are queued to be polled (i.e. they're
468 /// freshly spawned or they've been woken). Other tasks are not polled.
469 ///
470 /// You must call `poll` after receiving a call to `signal_fn`. It is OK
471 /// to call `poll` even when not requested by `signal_fn`, but it wastes
472 /// energy.
473 ///
474 /// # Safety
475 ///
476 /// You must NOT call `poll` reentrantly on the same executor.
477 ///
478 /// In particular, note that `poll` may call `signal_fn` synchronously. Therefore, you
479 /// must NOT directly call `poll()` from your `signal_fn`. Instead, `signal_fn` has to
480 /// somehow schedule for `poll()` to be called later, at a time you know for sure there's
481 /// no `poll()` already running.
482 pub unsafe fn poll(&'static self) {
483 self.inner.poll()
484 }
444 485
445 /// Get a spawner that spawns tasks in this executor. 486 /// Get a spawner that spawns tasks in this executor.
446 /// 487 ///
@@ -483,8 +524,10 @@ impl embassy_time::queue::TimerQueue for TimerQueue {
483 fn schedule_wake(&'static self, at: Instant, waker: &core::task::Waker) { 524 fn schedule_wake(&'static self, at: Instant, waker: &core::task::Waker) {
484 let task = waker::task_from_waker(waker); 525 let task = waker::task_from_waker(waker);
485 let task = task.header(); 526 let task = task.header();
486 let expires_at = task.expires_at.get(); 527 unsafe {
487 task.expires_at.set(expires_at.min(at)); 528 let expires_at = task.expires_at.get();
529 task.expires_at.set(expires_at.min(at));
530 }
488 } 531 }
489} 532}
490 533
diff --git a/embassy-executor/src/raw/timer_queue.rs b/embassy-executor/src/raw/timer_queue.rs
index 57d6d3cda..dc71c95b1 100644
--- a/embassy-executor/src/raw/timer_queue.rs
+++ b/embassy-executor/src/raw/timer_queue.rs
@@ -1,28 +1,32 @@
1use core::cell::Cell;
2use core::cmp::min; 1use core::cmp::min;
3 2
4use atomic_polyfill::Ordering; 3use atomic_polyfill::Ordering;
5use embassy_time::Instant; 4use embassy_time::Instant;
6 5
7use super::{TaskRef, STATE_TIMER_QUEUED}; 6use super::{TaskRef, STATE_TIMER_QUEUED};
7use crate::raw::util::SyncUnsafeCell;
8 8
9pub(crate) struct TimerQueueItem { 9pub(crate) struct TimerQueueItem {
10 next: Cell<Option<TaskRef>>, 10 next: SyncUnsafeCell<Option<TaskRef>>,
11} 11}
12 12
13impl TimerQueueItem { 13impl TimerQueueItem {
14 pub const fn new() -> Self { 14 pub const fn new() -> Self {
15 Self { next: Cell::new(None) } 15 Self {
16 next: SyncUnsafeCell::new(None),
17 }
16 } 18 }
17} 19}
18 20
19pub(crate) struct TimerQueue { 21pub(crate) struct TimerQueue {
20 head: Cell<Option<TaskRef>>, 22 head: SyncUnsafeCell<Option<TaskRef>>,
21} 23}
22 24
23impl TimerQueue { 25impl TimerQueue {
24 pub const fn new() -> Self { 26 pub const fn new() -> Self {
25 Self { head: Cell::new(None) } 27 Self {
28 head: SyncUnsafeCell::new(None),
29 }
26 } 30 }
27 31
28 pub(crate) unsafe fn update(&self, p: TaskRef) { 32 pub(crate) unsafe fn update(&self, p: TaskRef) {
diff --git a/embassy-executor/src/raw/util.rs b/embassy-executor/src/raw/util.rs
index 2b1f6b6f3..e2e8f4df8 100644
--- a/embassy-executor/src/raw/util.rs
+++ b/embassy-executor/src/raw/util.rs
@@ -25,3 +25,32 @@ impl<T> UninitCell<T> {
25 ptr::drop_in_place(self.as_mut_ptr()) 25 ptr::drop_in_place(self.as_mut_ptr())
26 } 26 }
27} 27}
28
29unsafe impl<T> Sync for UninitCell<T> {}
30
31#[repr(transparent)]
32pub struct SyncUnsafeCell<T> {
33 value: UnsafeCell<T>,
34}
35
36unsafe impl<T: Sync> Sync for SyncUnsafeCell<T> {}
37
38impl<T> SyncUnsafeCell<T> {
39 #[inline]
40 pub const fn new(value: T) -> Self {
41 Self {
42 value: UnsafeCell::new(value),
43 }
44 }
45
46 pub unsafe fn set(&self, value: T) {
47 *self.value.get() = value;
48 }
49
50 pub unsafe fn get(&self) -> T
51 where
52 T: Copy,
53 {
54 *self.value.get()
55 }
56}
diff --git a/embassy-executor/src/spawner.rs b/embassy-executor/src/spawner.rs
index 7c0a0183c..2b6224045 100644
--- a/embassy-executor/src/spawner.rs
+++ b/embassy-executor/src/spawner.rs
@@ -92,6 +92,7 @@ impl Spawner {
92 poll_fn(|cx| { 92 poll_fn(|cx| {
93 let task = raw::task_from_waker(cx.waker()); 93 let task = raw::task_from_waker(cx.waker());
94 let executor = unsafe { task.header().executor.get().unwrap_unchecked() }; 94 let executor = unsafe { task.header().executor.get().unwrap_unchecked() };
95 let executor = unsafe { raw::Executor::wrap(executor) };
95 Poll::Ready(Self::new(executor)) 96 Poll::Ready(Self::new(executor))
96 }) 97 })
97 .await 98 .await
@@ -130,9 +131,7 @@ impl Spawner {
130 /// spawner to other threads, but the spawner loses the ability to spawn 131 /// spawner to other threads, but the spawner loses the ability to spawn
131 /// non-Send tasks. 132 /// non-Send tasks.
132 pub fn make_send(&self) -> SendSpawner { 133 pub fn make_send(&self) -> SendSpawner {
133 SendSpawner { 134 SendSpawner::new(&self.executor.inner)
134 executor: self.executor,
135 }
136 } 135 }
137} 136}
138 137
@@ -145,14 +144,11 @@ impl Spawner {
145/// If you want to spawn non-Send tasks, use [Spawner]. 144/// If you want to spawn non-Send tasks, use [Spawner].
146#[derive(Copy, Clone)] 145#[derive(Copy, Clone)]
147pub struct SendSpawner { 146pub struct SendSpawner {
148 executor: &'static raw::Executor, 147 executor: &'static raw::SyncExecutor,
149} 148}
150 149
151unsafe impl Send for SendSpawner {}
152unsafe impl Sync for SendSpawner {}
153
154impl SendSpawner { 150impl SendSpawner {
155 pub(crate) fn new(executor: &'static raw::Executor) -> Self { 151 pub(crate) fn new(executor: &'static raw::SyncExecutor) -> Self {
156 Self { executor } 152 Self { executor }
157 } 153 }
158 154
diff --git a/embassy-rp/src/dma.rs b/embassy-rp/src/dma.rs
index 05adcecdd..ba07a88df 100644
--- a/embassy-rp/src/dma.rs
+++ b/embassy-rp/src/dma.rs
@@ -1,3 +1,4 @@
1//! Direct Memory Access (DMA)
1use core::future::Future; 2use core::future::Future;
2use core::pin::Pin; 3use core::pin::Pin;
3use core::sync::atomic::{compiler_fence, Ordering}; 4use core::sync::atomic::{compiler_fence, Ordering};
diff --git a/embassy-rp/src/spi.rs b/embassy-rp/src/spi.rs
index 584370d56..ebd621ecf 100644
--- a/embassy-rp/src/spi.rs
+++ b/embassy-rp/src/spi.rs
@@ -1,3 +1,4 @@
1//! Serial Peripheral Interface
1use core::marker::PhantomData; 2use core::marker::PhantomData;
2 3
3use embassy_embedded_hal::SetConfig; 4use embassy_embedded_hal::SetConfig;
@@ -383,21 +384,33 @@ impl<'d, T: Instance> Spi<'d, T, Async> {
383 } 384 }
384 385
385 async fn transfer_inner(&mut self, rx_ptr: *mut [u8], tx_ptr: *const [u8]) -> Result<(), Error> { 386 async fn transfer_inner(&mut self, rx_ptr: *mut [u8], tx_ptr: *const [u8]) -> Result<(), Error> {
386 let (_, from_len) = crate::dma::slice_ptr_parts(tx_ptr); 387 let (_, tx_len) = crate::dma::slice_ptr_parts(tx_ptr);
387 let (_, to_len) = crate::dma::slice_ptr_parts_mut(rx_ptr); 388 let (_, rx_len) = crate::dma::slice_ptr_parts_mut(rx_ptr);
388 assert_eq!(from_len, to_len); 389
389 unsafe { 390 unsafe {
390 self.inner.regs().dmacr().write(|reg| { 391 self.inner.regs().dmacr().write(|reg| {
391 reg.set_rxdmae(true); 392 reg.set_rxdmae(true);
392 reg.set_txdmae(true); 393 reg.set_txdmae(true);
393 }) 394 })
394 }; 395 };
395 let tx_ch = self.tx_dma.as_mut().unwrap(); 396
396 let tx_transfer = unsafe { 397 let mut tx_ch = self.tx_dma.as_mut().unwrap();
397 // If we don't assign future to a variable, the data register pointer 398 // If we don't assign future to a variable, the data register pointer
398 // is held across an await and makes the future non-Send. 399 // is held across an await and makes the future non-Send.
399 crate::dma::write(tx_ch, tx_ptr, self.inner.regs().dr().ptr() as *mut _, T::TX_DREQ) 400 let tx_transfer = async {
401 let p = self.inner.regs();
402 unsafe {
403 crate::dma::write(&mut tx_ch, tx_ptr, p.dr().ptr() as *mut _, T::TX_DREQ).await;
404
405 if rx_len > tx_len {
406 let write_bytes_len = rx_len - tx_len;
407 // write dummy data
408 // this will disable incrementation of the buffers
409 crate::dma::write_repeated(tx_ch, p.dr().ptr() as *mut u8, write_bytes_len, T::TX_DREQ).await
410 }
411 }
400 }; 412 };
413
401 let rx_ch = self.rx_dma.as_mut().unwrap(); 414 let rx_ch = self.rx_dma.as_mut().unwrap();
402 let rx_transfer = unsafe { 415 let rx_transfer = unsafe {
403 // If we don't assign future to a variable, the data register pointer 416 // If we don't assign future to a variable, the data register pointer
@@ -405,6 +418,22 @@ impl<'d, T: Instance> Spi<'d, T, Async> {
405 crate::dma::read(rx_ch, self.inner.regs().dr().ptr() as *const _, rx_ptr, T::RX_DREQ) 418 crate::dma::read(rx_ch, self.inner.regs().dr().ptr() as *const _, rx_ptr, T::RX_DREQ)
406 }; 419 };
407 join(tx_transfer, rx_transfer).await; 420 join(tx_transfer, rx_transfer).await;
421
422 // if tx > rx we should clear any overflow of the FIFO SPI buffer
423 if tx_len > rx_len {
424 let p = self.inner.regs();
425 unsafe {
426 while p.sr().read().bsy() {}
427
428 // clear RX FIFO contents to prevent stale reads
429 while p.sr().read().rne() {
430 let _: u16 = p.dr().read().data();
431 }
432 // clear RX overrun interrupt
433 p.icr().write(|w| w.set_roric(true));
434 }
435 }
436
408 Ok(()) 437 Ok(())
409 } 438 }
410} 439}
diff --git a/embassy-rp/src/uart/buffered.rs b/embassy-rp/src/uart/buffered.rs
index 32e5ddf14..1a573b311 100644
--- a/embassy-rp/src/uart/buffered.rs
+++ b/embassy-rp/src/uart/buffered.rs
@@ -124,7 +124,7 @@ impl<'d, T: Instance> BufferedUart<'d, T> {
124 } 124 }
125 } 125 }
126 126
127 pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> { 127 pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<usize, Error> {
128 self.tx.blocking_write(buffer) 128 self.tx.blocking_write(buffer)
129 } 129 }
130 130
@@ -132,7 +132,7 @@ impl<'d, T: Instance> BufferedUart<'d, T> {
132 self.tx.blocking_flush() 132 self.tx.blocking_flush()
133 } 133 }
134 134
135 pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { 135 pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<usize, Error> {
136 self.rx.blocking_read(buffer) 136 self.rx.blocking_read(buffer)
137 } 137 }
138 138
@@ -201,7 +201,7 @@ impl<'d, T: Instance> BufferedUartRx<'d, T> {
201 }) 201 })
202 } 202 }
203 203
204 pub fn blocking_read(&mut self, buf: &mut [u8]) -> Result<(), Error> { 204 pub fn blocking_read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
205 loop { 205 loop {
206 let state = T::state(); 206 let state = T::state();
207 let mut rx_reader = unsafe { state.rx_buf.reader() }; 207 let mut rx_reader = unsafe { state.rx_buf.reader() };
@@ -222,7 +222,7 @@ impl<'d, T: Instance> BufferedUartRx<'d, T> {
222 }); 222 });
223 } 223 }
224 224
225 return Ok(()); 225 return Ok(n);
226 } 226 }
227 } 227 }
228 } 228 }
@@ -326,7 +326,7 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> {
326 }) 326 })
327 } 327 }
328 328
329 pub fn blocking_write(&mut self, buf: &[u8]) -> Result<(), Error> { 329 pub fn blocking_write(&mut self, buf: &[u8]) -> Result<usize, Error> {
330 loop { 330 loop {
331 let state = T::state(); 331 let state = T::state();
332 let mut tx_writer = unsafe { state.tx_buf.writer() }; 332 let mut tx_writer = unsafe { state.tx_buf.writer() };
@@ -342,7 +342,7 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> {
342 // FIFO was empty we have to manually pend the interrupt to shovel 342 // FIFO was empty we have to manually pend the interrupt to shovel
343 // TX data from the buffer into the FIFO. 343 // TX data from the buffer into the FIFO.
344 unsafe { T::Interrupt::steal() }.pend(); 344 unsafe { T::Interrupt::steal() }.pend();
345 return Ok(()); 345 return Ok(n);
346 } 346 }
347 } 347 }
348 } 348 }
@@ -533,6 +533,38 @@ impl<'d, T: Instance + 'd> embedded_io::asynch::Write for BufferedUartTx<'d, T>
533 } 533 }
534} 534}
535 535
536impl<'d, T: Instance + 'd> embedded_io::blocking::Read for BufferedUart<'d, T> {
537 fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
538 self.rx.blocking_read(buf)
539 }
540}
541
542impl<'d, T: Instance + 'd> embedded_io::blocking::Read for BufferedUartRx<'d, T> {
543 fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
544 self.blocking_read(buf)
545 }
546}
547
548impl<'d, T: Instance + 'd> embedded_io::blocking::Write for BufferedUart<'d, T> {
549 fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
550 self.tx.blocking_write(buf)
551 }
552
553 fn flush(&mut self) -> Result<(), Self::Error> {
554 self.tx.blocking_flush()
555 }
556}
557
558impl<'d, T: Instance + 'd> embedded_io::blocking::Write for BufferedUartTx<'d, T> {
559 fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
560 self.blocking_write(buf)
561 }
562
563 fn flush(&mut self) -> Result<(), Self::Error> {
564 self.blocking_flush()
565 }
566}
567
536mod eh02 { 568mod eh02 {
537 use super::*; 569 use super::*;
538 570
@@ -566,8 +598,15 @@ mod eh02 {
566 impl<'d, T: Instance> embedded_hal_02::blocking::serial::Write<u8> for BufferedUartTx<'d, T> { 598 impl<'d, T: Instance> embedded_hal_02::blocking::serial::Write<u8> for BufferedUartTx<'d, T> {
567 type Error = Error; 599 type Error = Error;
568 600
569 fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> { 601 fn bwrite_all(&mut self, mut buffer: &[u8]) -> Result<(), Self::Error> {
570 self.blocking_write(buffer) 602 while !buffer.is_empty() {
603 match self.blocking_write(buffer) {
604 Ok(0) => panic!("zero-length write."),
605 Ok(n) => buffer = &buffer[n..],
606 Err(e) => return Err(e),
607 }
608 }
609 Ok(())
571 } 610 }
572 611
573 fn bflush(&mut self) -> Result<(), Self::Error> { 612 fn bflush(&mut self) -> Result<(), Self::Error> {
@@ -586,8 +625,15 @@ mod eh02 {
586 impl<'d, T: Instance> embedded_hal_02::blocking::serial::Write<u8> for BufferedUart<'d, T> { 625 impl<'d, T: Instance> embedded_hal_02::blocking::serial::Write<u8> for BufferedUart<'d, T> {
587 type Error = Error; 626 type Error = Error;
588 627
589 fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> { 628 fn bwrite_all(&mut self, mut buffer: &[u8]) -> Result<(), Self::Error> {
590 self.blocking_write(buffer) 629 while !buffer.is_empty() {
630 match self.blocking_write(buffer) {
631 Ok(0) => panic!("zero-length write."),
632 Ok(n) => buffer = &buffer[n..],
633 Err(e) => return Err(e),
634 }
635 }
636 Ok(())
591 } 637 }
592 638
593 fn bflush(&mut self) -> Result<(), Self::Error> { 639 fn bflush(&mut self) -> Result<(), Self::Error> {
@@ -620,7 +666,7 @@ mod eh1 {
620 666
621 impl<'d, T: Instance> embedded_hal_1::serial::Write for BufferedUartTx<'d, T> { 667 impl<'d, T: Instance> embedded_hal_1::serial::Write for BufferedUartTx<'d, T> {
622 fn write(&mut self, buffer: &[u8]) -> Result<(), Self::Error> { 668 fn write(&mut self, buffer: &[u8]) -> Result<(), Self::Error> {
623 self.blocking_write(buffer) 669 self.blocking_write(buffer).map(drop)
624 } 670 }
625 671
626 fn flush(&mut self) -> Result<(), Self::Error> { 672 fn flush(&mut self) -> Result<(), Self::Error> {
@@ -630,7 +676,7 @@ mod eh1 {
630 676
631 impl<'d, T: Instance> embedded_hal_nb::serial::Write for BufferedUartTx<'d, T> { 677 impl<'d, T: Instance> embedded_hal_nb::serial::Write for BufferedUartTx<'d, T> {
632 fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> { 678 fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> {
633 self.blocking_write(&[char]).map_err(nb::Error::Other) 679 self.blocking_write(&[char]).map(drop).map_err(nb::Error::Other)
634 } 680 }
635 681
636 fn flush(&mut self) -> nb::Result<(), Self::Error> { 682 fn flush(&mut self) -> nb::Result<(), Self::Error> {
@@ -646,7 +692,7 @@ mod eh1 {
646 692
647 impl<'d, T: Instance> embedded_hal_1::serial::Write for BufferedUart<'d, T> { 693 impl<'d, T: Instance> embedded_hal_1::serial::Write for BufferedUart<'d, T> {
648 fn write(&mut self, buffer: &[u8]) -> Result<(), Self::Error> { 694 fn write(&mut self, buffer: &[u8]) -> Result<(), Self::Error> {
649 self.blocking_write(buffer) 695 self.blocking_write(buffer).map(drop)
650 } 696 }
651 697
652 fn flush(&mut self) -> Result<(), Self::Error> { 698 fn flush(&mut self) -> Result<(), Self::Error> {
@@ -656,7 +702,7 @@ mod eh1 {
656 702
657 impl<'d, T: Instance> embedded_hal_nb::serial::Write for BufferedUart<'d, T> { 703 impl<'d, T: Instance> embedded_hal_nb::serial::Write for BufferedUart<'d, T> {
658 fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> { 704 fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> {
659 self.blocking_write(&[char]).map_err(nb::Error::Other) 705 self.blocking_write(&[char]).map(drop).map_err(nb::Error::Other)
660 } 706 }
661 707
662 fn flush(&mut self) -> nb::Result<(), Self::Error> { 708 fn flush(&mut self) -> nb::Result<(), Self::Error> {
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml
index b66d724d5..14ec3d70a 100644
--- a/embassy-stm32/Cargo.toml
+++ b/embassy-stm32/Cargo.toml
@@ -60,7 +60,7 @@ sdio-host = "0.5.0"
60embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "46d1b1c2ff13e31e282ec1e352421721694f126a", optional = true } 60embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "46d1b1c2ff13e31e282ec1e352421721694f126a", optional = true }
61critical-section = "1.1" 61critical-section = "1.1"
62atomic-polyfill = "1.0.1" 62atomic-polyfill = "1.0.1"
63stm32-metapac = { version = "1", features = ["rt"] } 63stm32-metapac = { version = "2", features = ["rt"] }
64vcell = "0.1.3" 64vcell = "0.1.3"
65bxcan = "0.7.0" 65bxcan = "0.7.0"
66nb = "1.0.0" 66nb = "1.0.0"
@@ -72,7 +72,7 @@ embedded-io = { version = "0.4.0", features = ["async"], optional = true }
72[build-dependencies] 72[build-dependencies]
73proc-macro2 = "1.0.36" 73proc-macro2 = "1.0.36"
74quote = "1.0.15" 74quote = "1.0.15"
75stm32-metapac = { version = "1", default-features = false, features = ["metadata"]} 75stm32-metapac = { version = "2", default-features = false, features = ["metadata"]}
76 76
77[features] 77[features]
78defmt = ["dep:defmt", "bxcan/unstable-defmt", "embassy-sync/defmt", "embassy-executor/defmt", "embassy-embedded-hal/defmt", "embassy-hal-common/defmt", "embedded-io?/defmt", "embassy-usb-driver?/defmt", "embassy-net-driver/defmt"] 78defmt = ["dep:defmt", "bxcan/unstable-defmt", "embassy-sync/defmt", "embassy-executor/defmt", "embassy-embedded-hal/defmt", "embassy-hal-common/defmt", "embedded-io?/defmt", "embassy-usb-driver?/defmt", "embassy-net-driver/defmt"]
diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs
index dbfc1370d..3780c5a40 100644
--- a/embassy-stm32/build.rs
+++ b/embassy-stm32/build.rs
@@ -427,6 +427,12 @@ fn main() {
427 (("sdmmc", "D6"), quote!(crate::sdmmc::D6Pin)), 427 (("sdmmc", "D6"), quote!(crate::sdmmc::D6Pin)),
428 (("sdmmc", "D6"), quote!(crate::sdmmc::D7Pin)), 428 (("sdmmc", "D6"), quote!(crate::sdmmc::D7Pin)),
429 (("sdmmc", "D8"), quote!(crate::sdmmc::D8Pin)), 429 (("sdmmc", "D8"), quote!(crate::sdmmc::D8Pin)),
430 (("quadspi", "BK1_IO0"), quote!(crate::qspi::D0Pin)),
431 (("quadspi", "BK1_IO1"), quote!(crate::qspi::D1Pin)),
432 (("quadspi", "BK1_IO2"), quote!(crate::qspi::D2Pin)),
433 (("quadspi", "BK1_IO3"), quote!(crate::qspi::D3Pin)),
434 (("quadspi", "CLK"), quote!(crate::qspi::SckPin)),
435 (("quadspi", "BK1_NCS"), quote!(crate::qspi::NSSPin)),
430 ].into(); 436 ].into();
431 437
432 for p in METADATA.peripherals { 438 for p in METADATA.peripherals {
@@ -507,6 +513,7 @@ fn main() {
507 (("dcmi", "PSSI"), quote!(crate::dcmi::FrameDma)), 513 (("dcmi", "PSSI"), quote!(crate::dcmi::FrameDma)),
508 // SDMMCv1 uses the same channel for both directions, so just implement for RX 514 // SDMMCv1 uses the same channel for both directions, so just implement for RX
509 (("sdmmc", "RX"), quote!(crate::sdmmc::SdmmcDma)), 515 (("sdmmc", "RX"), quote!(crate::sdmmc::SdmmcDma)),
516 (("quadspi", "QUADSPI"), quote!(crate::qspi::QuadDma)),
510 ] 517 ]
511 .into(); 518 .into();
512 519
diff --git a/embassy-stm32/src/adc/sample_time.rs b/embassy-stm32/src/adc/sample_time.rs
index 60ba80048..bc5fb1d6f 100644
--- a/embassy-stm32/src/adc/sample_time.rs
+++ b/embassy-stm32/src/adc/sample_time.rs
@@ -1,5 +1,5 @@
1macro_rules! impl_sample_time { 1macro_rules! impl_sample_time {
2 ($default_doc:expr, $default:ident, $pac:ty, ($(($doc:expr, $variant:ident, $pac_variant:ident)),*)) => { 2 ($default_doc:expr, $default:ident, ($(($doc:expr, $variant:ident, $pac_variant:ident)),*)) => {
3 #[doc = concat!("ADC sample time\n\nThe default setting is ", $default_doc, " ADC clock cycles.")] 3 #[doc = concat!("ADC sample time\n\nThe default setting is ", $default_doc, " ADC clock cycles.")]
4 #[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)] 4 #[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
5 pub enum SampleTime { 5 pub enum SampleTime {
@@ -9,10 +9,10 @@ macro_rules! impl_sample_time {
9 )* 9 )*
10 } 10 }
11 11
12 impl From<SampleTime> for $pac { 12 impl From<SampleTime> for crate::pac::adc::vals::SampleTime {
13 fn from(sample_time: SampleTime) -> $pac { 13 fn from(sample_time: SampleTime) -> crate::pac::adc::vals::SampleTime {
14 match sample_time { 14 match sample_time {
15 $(SampleTime::$variant => <$pac>::$pac_variant),* 15 $(SampleTime::$variant => crate::pac::adc::vals::SampleTime::$pac_variant),*
16 } 16 }
17 } 17 }
18 } 18 }
@@ -29,7 +29,6 @@ macro_rules! impl_sample_time {
29impl_sample_time!( 29impl_sample_time!(
30 "1.5", 30 "1.5",
31 Cycles1_5, 31 Cycles1_5,
32 crate::pac::adc::vals::SampleTime,
33 ( 32 (
34 ("1.5", Cycles1_5, CYCLES1_5), 33 ("1.5", Cycles1_5, CYCLES1_5),
35 ("7.5", Cycles7_5, CYCLES7_5), 34 ("7.5", Cycles7_5, CYCLES7_5),
@@ -46,7 +45,6 @@ impl_sample_time!(
46impl_sample_time!( 45impl_sample_time!(
47 "3", 46 "3",
48 Cycles3, 47 Cycles3,
49 crate::pac::adc::vals::Smp,
50 ( 48 (
51 ("3", Cycles3, CYCLES3), 49 ("3", Cycles3, CYCLES3),
52 ("15", Cycles15, CYCLES15), 50 ("15", Cycles15, CYCLES15),
@@ -63,7 +61,6 @@ impl_sample_time!(
63impl_sample_time!( 61impl_sample_time!(
64 "2.5", 62 "2.5",
65 Cycles2_5, 63 Cycles2_5,
66 crate::pac::adc::vals::SampleTime,
67 ( 64 (
68 ("2.5", Cycles2_5, CYCLES2_5), 65 ("2.5", Cycles2_5, CYCLES2_5),
69 ("6.5", Cycles6_5, CYCLES6_5), 66 ("6.5", Cycles6_5, CYCLES6_5),
@@ -80,7 +77,6 @@ impl_sample_time!(
80impl_sample_time!( 77impl_sample_time!(
81 "1.5", 78 "1.5",
82 Cycles1_5, 79 Cycles1_5,
83 crate::pac::adc::vals::SampleTime,
84 ( 80 (
85 ("1.5", Cycles1_5, CYCLES1_5), 81 ("1.5", Cycles1_5, CYCLES1_5),
86 ("3.5", Cycles3_5, CYCLES3_5), 82 ("3.5", Cycles3_5, CYCLES3_5),
@@ -97,7 +93,6 @@ impl_sample_time!(
97impl_sample_time!( 93impl_sample_time!(
98 "1.5", 94 "1.5",
99 Cycles1_5, 95 Cycles1_5,
100 crate::pac::adc::vals::Smp,
101 ( 96 (
102 ("1.5", Cycles1_5, CYCLES1_5), 97 ("1.5", Cycles1_5, CYCLES1_5),
103 ("2.5", Cycles2_5, CYCLES2_5), 98 ("2.5", Cycles2_5, CYCLES2_5),
diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs
index eeaa04f67..8dc4df2dc 100644
--- a/embassy-stm32/src/lib.rs
+++ b/embassy-stm32/src/lib.rs
@@ -48,6 +48,8 @@ pub mod crc;
48))] 48))]
49pub mod flash; 49pub mod flash;
50pub mod pwm; 50pub mod pwm;
51#[cfg(quadspi)]
52pub mod qspi;
51#[cfg(rng)] 53#[cfg(rng)]
52pub mod rng; 54pub mod rng;
53#[cfg(sdmmc)] 55#[cfg(sdmmc)]
@@ -60,7 +62,6 @@ pub mod usart;
60pub mod usb; 62pub mod usb;
61#[cfg(otg)] 63#[cfg(otg)]
62pub mod usb_otg; 64pub mod usb_otg;
63
64#[cfg(iwdg)] 65#[cfg(iwdg)]
65pub mod wdg; 66pub mod wdg;
66 67
diff --git a/embassy-stm32/src/qspi/enums.rs b/embassy-stm32/src/qspi/enums.rs
new file mode 100644
index 000000000..2dbe2b061
--- /dev/null
+++ b/embassy-stm32/src/qspi/enums.rs
@@ -0,0 +1,294 @@
1#[allow(dead_code)]
2#[derive(Copy, Clone)]
3pub(crate) enum QspiMode {
4 IndirectWrite,
5 IndirectRead,
6 AutoPolling,
7 MemoryMapped,
8}
9
10impl Into<u8> for QspiMode {
11 fn into(self) -> u8 {
12 match self {
13 QspiMode::IndirectWrite => 0b00,
14 QspiMode::IndirectRead => 0b01,
15 QspiMode::AutoPolling => 0b10,
16 QspiMode::MemoryMapped => 0b11,
17 }
18 }
19}
20
21#[allow(dead_code)]
22#[derive(Copy, Clone)]
23pub enum QspiWidth {
24 NONE,
25 SING,
26 DUAL,
27 QUAD,
28}
29
30impl Into<u8> for QspiWidth {
31 fn into(self) -> u8 {
32 match self {
33 QspiWidth::NONE => 0b00,
34 QspiWidth::SING => 0b01,
35 QspiWidth::DUAL => 0b10,
36 QspiWidth::QUAD => 0b11,
37 }
38 }
39}
40
41#[derive(Copy, Clone)]
42pub enum MemorySize {
43 _1KiB,
44 _2KiB,
45 _4KiB,
46 _8KiB,
47 _16KiB,
48 _32KiB,
49 _64KiB,
50 _128KiB,
51 _256KiB,
52 _512KiB,
53 _1MiB,
54 _2MiB,
55 _4MiB,
56 _8MiB,
57 _16MiB,
58 _32MiB,
59 _64MiB,
60 _128MiB,
61 _256MiB,
62 _512MiB,
63 _1GiB,
64 _2GiB,
65 _4GiB,
66 Other(u8),
67}
68
69impl Into<u8> for MemorySize {
70 fn into(self) -> u8 {
71 match self {
72 MemorySize::_1KiB => 9,
73 MemorySize::_2KiB => 10,
74 MemorySize::_4KiB => 11,
75 MemorySize::_8KiB => 12,
76 MemorySize::_16KiB => 13,
77 MemorySize::_32KiB => 14,
78 MemorySize::_64KiB => 15,
79 MemorySize::_128KiB => 16,
80 MemorySize::_256KiB => 17,
81 MemorySize::_512KiB => 18,
82 MemorySize::_1MiB => 19,
83 MemorySize::_2MiB => 20,
84 MemorySize::_4MiB => 21,
85 MemorySize::_8MiB => 22,
86 MemorySize::_16MiB => 23,
87 MemorySize::_32MiB => 24,
88 MemorySize::_64MiB => 25,
89 MemorySize::_128MiB => 26,
90 MemorySize::_256MiB => 27,
91 MemorySize::_512MiB => 28,
92 MemorySize::_1GiB => 29,
93 MemorySize::_2GiB => 30,
94 MemorySize::_4GiB => 31,
95 MemorySize::Other(val) => val,
96 }
97 }
98}
99
100#[derive(Copy, Clone)]
101pub enum AddressSize {
102 _8Bit,
103 _16Bit,
104 _24bit,
105 _32bit,
106}
107
108impl Into<u8> for AddressSize {
109 fn into(self) -> u8 {
110 match self {
111 AddressSize::_8Bit => 0b00,
112 AddressSize::_16Bit => 0b01,
113 AddressSize::_24bit => 0b10,
114 AddressSize::_32bit => 0b11,
115 }
116 }
117}
118
119#[derive(Copy, Clone)]
120pub enum ChipSelectHightTime {
121 _1Cycle,
122 _2Cycle,
123 _3Cycle,
124 _4Cycle,
125 _5Cycle,
126 _6Cycle,
127 _7Cycle,
128 _8Cycle,
129}
130
131impl Into<u8> for ChipSelectHightTime {
132 fn into(self) -> u8 {
133 match self {
134 ChipSelectHightTime::_1Cycle => 0,
135 ChipSelectHightTime::_2Cycle => 1,
136 ChipSelectHightTime::_3Cycle => 2,
137 ChipSelectHightTime::_4Cycle => 3,
138 ChipSelectHightTime::_5Cycle => 4,
139 ChipSelectHightTime::_6Cycle => 5,
140 ChipSelectHightTime::_7Cycle => 6,
141 ChipSelectHightTime::_8Cycle => 7,
142 }
143 }
144}
145
146#[derive(Copy, Clone)]
147pub enum FIFOThresholdLevel {
148 _1Bytes,
149 _2Bytes,
150 _3Bytes,
151 _4Bytes,
152 _5Bytes,
153 _6Bytes,
154 _7Bytes,
155 _8Bytes,
156 _9Bytes,
157 _10Bytes,
158 _11Bytes,
159 _12Bytes,
160 _13Bytes,
161 _14Bytes,
162 _15Bytes,
163 _16Bytes,
164 _17Bytes,
165 _18Bytes,
166 _19Bytes,
167 _20Bytes,
168 _21Bytes,
169 _22Bytes,
170 _23Bytes,
171 _24Bytes,
172 _25Bytes,
173 _26Bytes,
174 _27Bytes,
175 _28Bytes,
176 _29Bytes,
177 _30Bytes,
178 _31Bytes,
179 _32Bytes,
180}
181
182impl Into<u8> for FIFOThresholdLevel {
183 fn into(self) -> u8 {
184 match self {
185 FIFOThresholdLevel::_1Bytes => 0,
186 FIFOThresholdLevel::_2Bytes => 1,
187 FIFOThresholdLevel::_3Bytes => 2,
188 FIFOThresholdLevel::_4Bytes => 3,
189 FIFOThresholdLevel::_5Bytes => 4,
190 FIFOThresholdLevel::_6Bytes => 5,
191 FIFOThresholdLevel::_7Bytes => 6,
192 FIFOThresholdLevel::_8Bytes => 7,
193 FIFOThresholdLevel::_9Bytes => 8,
194 FIFOThresholdLevel::_10Bytes => 9,
195 FIFOThresholdLevel::_11Bytes => 10,
196 FIFOThresholdLevel::_12Bytes => 11,
197 FIFOThresholdLevel::_13Bytes => 12,
198 FIFOThresholdLevel::_14Bytes => 13,
199 FIFOThresholdLevel::_15Bytes => 14,
200 FIFOThresholdLevel::_16Bytes => 15,
201 FIFOThresholdLevel::_17Bytes => 16,
202 FIFOThresholdLevel::_18Bytes => 17,
203 FIFOThresholdLevel::_19Bytes => 18,
204 FIFOThresholdLevel::_20Bytes => 19,
205 FIFOThresholdLevel::_21Bytes => 20,
206 FIFOThresholdLevel::_22Bytes => 21,
207 FIFOThresholdLevel::_23Bytes => 22,
208 FIFOThresholdLevel::_24Bytes => 23,
209 FIFOThresholdLevel::_25Bytes => 24,
210 FIFOThresholdLevel::_26Bytes => 25,
211 FIFOThresholdLevel::_27Bytes => 26,
212 FIFOThresholdLevel::_28Bytes => 27,
213 FIFOThresholdLevel::_29Bytes => 28,
214 FIFOThresholdLevel::_30Bytes => 29,
215 FIFOThresholdLevel::_31Bytes => 30,
216 FIFOThresholdLevel::_32Bytes => 31,
217 }
218 }
219}
220
221#[derive(Copy, Clone)]
222pub enum DummyCycles {
223 _0,
224 _1,
225 _2,
226 _3,
227 _4,
228 _5,
229 _6,
230 _7,
231 _8,
232 _9,
233 _10,
234 _11,
235 _12,
236 _13,
237 _14,
238 _15,
239 _16,
240 _17,
241 _18,
242 _19,
243 _20,
244 _21,
245 _22,
246 _23,
247 _24,
248 _25,
249 _26,
250 _27,
251 _28,
252 _29,
253 _30,
254 _31,
255}
256
257impl Into<u8> for DummyCycles {
258 fn into(self) -> u8 {
259 match self {
260 DummyCycles::_0 => 0,
261 DummyCycles::_1 => 1,
262 DummyCycles::_2 => 2,
263 DummyCycles::_3 => 3,
264 DummyCycles::_4 => 4,
265 DummyCycles::_5 => 5,
266 DummyCycles::_6 => 6,
267 DummyCycles::_7 => 7,
268 DummyCycles::_8 => 8,
269 DummyCycles::_9 => 9,
270 DummyCycles::_10 => 10,
271 DummyCycles::_11 => 11,
272 DummyCycles::_12 => 12,
273 DummyCycles::_13 => 13,
274 DummyCycles::_14 => 14,
275 DummyCycles::_15 => 15,
276 DummyCycles::_16 => 16,
277 DummyCycles::_17 => 17,
278 DummyCycles::_18 => 18,
279 DummyCycles::_19 => 19,
280 DummyCycles::_20 => 20,
281 DummyCycles::_21 => 21,
282 DummyCycles::_22 => 22,
283 DummyCycles::_23 => 23,
284 DummyCycles::_24 => 24,
285 DummyCycles::_25 => 25,
286 DummyCycles::_26 => 26,
287 DummyCycles::_27 => 27,
288 DummyCycles::_28 => 28,
289 DummyCycles::_29 => 29,
290 DummyCycles::_30 => 30,
291 DummyCycles::_31 => 31,
292 }
293 }
294}
diff --git a/embassy-stm32/src/qspi/mod.rs b/embassy-stm32/src/qspi/mod.rs
new file mode 100644
index 000000000..f33319620
--- /dev/null
+++ b/embassy-stm32/src/qspi/mod.rs
@@ -0,0 +1,338 @@
1#![macro_use]
2
3pub mod enums;
4
5use embassy_hal_common::{into_ref, PeripheralRef};
6use enums::*;
7
8use crate::dma::TransferOptions;
9use crate::gpio::sealed::AFType;
10use crate::gpio::AnyPin;
11use crate::pac::quadspi::Quadspi as Regs;
12use crate::rcc::RccPeripheral;
13use crate::{peripherals, Peripheral};
14
15pub struct TransferConfig {
16 /// Instraction width (IMODE)
17 pub iwidth: QspiWidth,
18 /// Address width (ADMODE)
19 pub awidth: QspiWidth,
20 /// Data width (DMODE)
21 pub dwidth: QspiWidth,
22 /// Instruction Id
23 pub instruction: u8,
24 /// Flash memory address
25 pub address: Option<u32>,
26 /// Number of dummy cycles (DCYC)
27 pub dummy: DummyCycles,
28 /// Length of data
29 pub data_len: Option<usize>,
30}
31
32impl Default for TransferConfig {
33 fn default() -> Self {
34 Self {
35 iwidth: QspiWidth::NONE,
36 awidth: QspiWidth::NONE,
37 dwidth: QspiWidth::NONE,
38 instruction: 0,
39 address: None,
40 dummy: DummyCycles::_0,
41 data_len: None,
42 }
43 }
44}
45
46pub struct Config {
47 /// Flash memory size representend as 2^[0-32], as reasonable minimum 1KiB(9) was chosen.
48 /// If you need other value the whose predefined use `Other` variant.
49 pub memory_size: MemorySize,
50 /// Address size (8/16/24/32-bit)
51 pub address_size: AddressSize,
52 /// Scalar factor for generating CLK [0-255]
53 pub prescaler: u8,
54 /// Number of bytes to trigger FIFO threshold flag.
55 pub fifo_threshold: FIFOThresholdLevel,
56 /// Minimum number of cycles that chip select must be high between issued commands
57 pub cs_high_time: ChipSelectHightTime,
58}
59
60impl Default for Config {
61 fn default() -> Self {
62 Self {
63 memory_size: MemorySize::Other(0),
64 address_size: AddressSize::_24bit,
65 prescaler: 128,
66 fifo_threshold: FIFOThresholdLevel::_17Bytes,
67 cs_high_time: ChipSelectHightTime::_5Cycle,
68 }
69 }
70}
71
72#[allow(dead_code)]
73pub struct Qspi<'d, T: Instance, Dma> {
74 _peri: PeripheralRef<'d, T>,
75 sck: Option<PeripheralRef<'d, AnyPin>>,
76 d0: Option<PeripheralRef<'d, AnyPin>>,
77 d1: Option<PeripheralRef<'d, AnyPin>>,
78 d2: Option<PeripheralRef<'d, AnyPin>>,
79 d3: Option<PeripheralRef<'d, AnyPin>>,
80 nss: Option<PeripheralRef<'d, AnyPin>>,
81 dma: PeripheralRef<'d, Dma>,
82 config: Config,
83}
84
85impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
86 pub fn new(
87 peri: impl Peripheral<P = T> + 'd,
88 d0: impl Peripheral<P = impl D0Pin<T>> + 'd,
89 d1: impl Peripheral<P = impl D1Pin<T>> + 'd,
90 d2: impl Peripheral<P = impl D2Pin<T>> + 'd,
91 d3: impl Peripheral<P = impl D3Pin<T>> + 'd,
92 sck: impl Peripheral<P = impl SckPin<T>> + 'd,
93 nss: impl Peripheral<P = impl NSSPin<T>> + 'd,
94 dma: impl Peripheral<P = Dma> + 'd,
95 config: Config,
96 ) -> Self {
97 into_ref!(peri, d0, d1, d2, d3, sck, nss);
98
99 unsafe {
100 sck.set_as_af(sck.af_num(), AFType::OutputPushPull);
101 sck.set_speed(crate::gpio::Speed::VeryHigh);
102 nss.set_as_af(nss.af_num(), AFType::OutputPushPull);
103 nss.set_speed(crate::gpio::Speed::VeryHigh);
104 d0.set_as_af(d0.af_num(), AFType::OutputPushPull);
105 d0.set_speed(crate::gpio::Speed::VeryHigh);
106 d1.set_as_af(d1.af_num(), AFType::OutputPushPull);
107 d1.set_speed(crate::gpio::Speed::VeryHigh);
108 d2.set_as_af(d2.af_num(), AFType::OutputPushPull);
109 d2.set_speed(crate::gpio::Speed::VeryHigh);
110 d3.set_as_af(d3.af_num(), AFType::OutputPushPull);
111 d3.set_speed(crate::gpio::Speed::VeryHigh);
112 }
113
114 Self::new_inner(
115 peri,
116 Some(d0.map_into()),
117 Some(d1.map_into()),
118 Some(d2.map_into()),
119 Some(d3.map_into()),
120 Some(sck.map_into()),
121 Some(nss.map_into()),
122 dma,
123 config,
124 )
125 }
126
127 fn new_inner(
128 peri: impl Peripheral<P = T> + 'd,
129 d0: Option<PeripheralRef<'d, AnyPin>>,
130 d1: Option<PeripheralRef<'d, AnyPin>>,
131 d2: Option<PeripheralRef<'d, AnyPin>>,
132 d3: Option<PeripheralRef<'d, AnyPin>>,
133 sck: Option<PeripheralRef<'d, AnyPin>>,
134 nss: Option<PeripheralRef<'d, AnyPin>>,
135 dma: impl Peripheral<P = Dma> + 'd,
136 config: Config,
137 ) -> Self {
138 into_ref!(peri, dma);
139
140 T::enable();
141 unsafe {
142 T::REGS.cr().write(|w| w.set_fthres(config.fifo_threshold.into()));
143
144 while T::REGS.sr().read().busy() {}
145
146 T::REGS.cr().write(|w| {
147 w.set_prescaler(config.prescaler);
148 w.set_en(true);
149 });
150 T::REGS.dcr().write(|w| {
151 w.set_fsize(config.memory_size.into());
152 w.set_csht(config.cs_high_time.into());
153 w.set_ckmode(false);
154 });
155 }
156
157 Self {
158 _peri: peri,
159 sck,
160 d0,
161 d1,
162 d2,
163 d3,
164 nss,
165 dma,
166 config,
167 }
168 }
169
170 pub fn command(&mut self, transaction: TransferConfig) {
171 unsafe {
172 T::REGS.cr().modify(|v| v.set_dmaen(false));
173 self.setup_transaction(QspiMode::IndirectWrite, &transaction);
174
175 while !T::REGS.sr().read().tcf() {}
176 T::REGS.fcr().modify(|v| v.set_ctcf(true));
177 }
178 }
179
180 pub fn blocking_read(&mut self, buf: &mut [u8], transaction: TransferConfig) {
181 unsafe {
182 T::REGS.cr().modify(|v| v.set_dmaen(false));
183 self.setup_transaction(QspiMode::IndirectWrite, &transaction);
184
185 if let Some(len) = transaction.data_len {
186 let current_ar = T::REGS.ar().read().address();
187 T::REGS.ccr().modify(|v| {
188 v.set_fmode(QspiMode::IndirectRead.into());
189 });
190 T::REGS.ar().write(|v| {
191 v.set_address(current_ar);
192 });
193
194 for idx in 0..len {
195 while !T::REGS.sr().read().tcf() && !T::REGS.sr().read().ftf() {}
196 buf[idx] = *(T::REGS.dr().ptr() as *mut u8);
197 }
198 }
199
200 while !T::REGS.sr().read().tcf() {}
201 T::REGS.fcr().modify(|v| v.set_ctcf(true));
202 }
203 }
204
205 pub fn blocking_write(&mut self, buf: &[u8], transaction: TransferConfig) {
206 unsafe {
207 T::REGS.cr().modify(|v| v.set_dmaen(false));
208 self.setup_transaction(QspiMode::IndirectWrite, &transaction);
209
210 if let Some(len) = transaction.data_len {
211 T::REGS.ccr().modify(|v| {
212 v.set_fmode(QspiMode::IndirectWrite.into());
213 });
214
215 for idx in 0..len {
216 while !T::REGS.sr().read().ftf() {}
217 *(T::REGS.dr().ptr() as *mut u8) = buf[idx];
218 }
219 }
220
221 while !T::REGS.sr().read().tcf() {}
222 T::REGS.fcr().modify(|v| v.set_ctcf(true));
223 }
224 }
225
226 pub fn blocking_read_dma(&mut self, buf: &mut [u8], transaction: TransferConfig)
227 where
228 Dma: QuadDma<T>,
229 {
230 unsafe {
231 self.setup_transaction(QspiMode::IndirectWrite, &transaction);
232
233 let request = self.dma.request();
234 let options = TransferOptions::default();
235
236 T::REGS.ccr().modify(|v| {
237 v.set_fmode(QspiMode::IndirectRead.into());
238 });
239 let current_ar = T::REGS.ar().read().address();
240 T::REGS.ar().write(|v| {
241 v.set_address(current_ar);
242 });
243
244 self.dma
245 .start_read(request, T::REGS.dr().ptr() as *mut u8, buf, options);
246
247 T::REGS.cr().modify(|v| v.set_dmaen(true));
248
249 while self.dma.is_running() {}
250 }
251 }
252
253 pub fn blocking_write_dma(&mut self, buf: &[u8], transaction: TransferConfig)
254 where
255 Dma: QuadDma<T>,
256 {
257 unsafe {
258 self.setup_transaction(QspiMode::IndirectWrite, &transaction);
259
260 let request = self.dma.request();
261 let options = TransferOptions::default();
262
263 T::REGS.ccr().modify(|v| {
264 v.set_fmode(QspiMode::IndirectWrite.into());
265 });
266
267 self.dma
268 .start_write(request, buf, T::REGS.dr().ptr() as *mut u8, options);
269
270 T::REGS.cr().modify(|v| v.set_dmaen(true));
271
272 while self.dma.is_running() {}
273 }
274 }
275
276 fn setup_transaction(&mut self, fmode: QspiMode, transaction: &TransferConfig) {
277 unsafe {
278 T::REGS.fcr().modify(|v| {
279 v.set_csmf(true);
280 v.set_ctcf(true);
281 v.set_ctef(true);
282 v.set_ctof(true);
283 });
284
285 while T::REGS.sr().read().busy() {}
286
287 if let Some(len) = transaction.data_len {
288 T::REGS.dlr().write(|v| v.set_dl(len as u32 - 1));
289 }
290
291 T::REGS.ccr().write(|v| {
292 v.set_fmode(fmode.into());
293 v.set_imode(transaction.iwidth.into());
294 v.set_instruction(transaction.instruction);
295 v.set_admode(transaction.awidth.into());
296 v.set_adsize(self.config.address_size.into());
297 v.set_dmode(transaction.dwidth.into());
298 v.set_abmode(QspiWidth::NONE.into());
299 v.set_dcyc(transaction.dummy.into());
300 });
301
302 if let Some(addr) = transaction.address {
303 T::REGS.ar().write(|v| {
304 v.set_address(addr);
305 });
306 }
307 }
308 }
309}
310
311pub(crate) mod sealed {
312 use super::*;
313
314 pub trait Instance {
315 const REGS: Regs;
316 }
317}
318
319pub trait Instance: Peripheral<P = Self> + sealed::Instance + RccPeripheral {}
320
321pin_trait!(SckPin, Instance);
322pin_trait!(D0Pin, Instance);
323pin_trait!(D1Pin, Instance);
324pin_trait!(D2Pin, Instance);
325pin_trait!(D3Pin, Instance);
326pin_trait!(NSSPin, Instance);
327
328dma_trait!(QuadDma, Instance);
329
330foreach_peripheral!(
331 (quadspi, $inst:ident) => {
332 impl sealed::Instance for peripherals::$inst {
333 const REGS: Regs = crate::pac::$inst;
334 }
335
336 impl Instance for peripherals::$inst {}
337 };
338);
diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs
index a27fcc1ca..cd7d72f91 100644
--- a/embassy-stm32/src/usart/buffered.rs
+++ b/embassy-stm32/src/usart/buffered.rs
@@ -197,6 +197,40 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> {
197 .await 197 .await
198 } 198 }
199 199
200 fn inner_blocking_read(&self, buf: &mut [u8]) -> Result<usize, Error> {
201 loop {
202 let mut do_pend = false;
203 let mut inner = self.inner.borrow_mut();
204 let n = inner.with(|state| {
205 compiler_fence(Ordering::SeqCst);
206
207 // We have data ready in buffer? Return it.
208 let data = state.rx.pop_buf();
209 if !data.is_empty() {
210 let len = data.len().min(buf.len());
211 buf[..len].copy_from_slice(&data[..len]);
212
213 if state.rx.is_full() {
214 do_pend = true;
215 }
216 state.rx.pop(len);
217
218 return len;
219 }
220
221 0
222 });
223
224 if do_pend {
225 inner.pend();
226 }
227
228 if n > 0 {
229 return Ok(n);
230 }
231 }
232 }
233
200 async fn inner_write<'a>(&'a self, buf: &'a [u8]) -> Result<usize, Error> { 234 async fn inner_write<'a>(&'a self, buf: &'a [u8]) -> Result<usize, Error> {
201 poll_fn(move |cx| { 235 poll_fn(move |cx| {
202 let mut inner = self.inner.borrow_mut(); 236 let mut inner = self.inner.borrow_mut();
@@ -236,6 +270,39 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> {
236 .await 270 .await
237 } 271 }
238 272
273 fn inner_blocking_write(&self, buf: &[u8]) -> Result<usize, Error> {
274 loop {
275 let mut inner = self.inner.borrow_mut();
276 let (n, empty) = inner.with(|state| {
277 let empty = state.tx.is_empty();
278 let tx_buf = state.tx.push_buf();
279 if tx_buf.is_empty() {
280 return (0, empty);
281 }
282
283 let n = core::cmp::min(tx_buf.len(), buf.len());
284 tx_buf[..n].copy_from_slice(&buf[..n]);
285 state.tx.push(n);
286
287 (n, empty)
288 });
289 if empty {
290 inner.pend();
291 }
292 if n != 0 {
293 return Ok(n);
294 }
295 }
296 }
297
298 fn inner_blocking_flush(&self) -> Result<(), Error> {
299 loop {
300 if !self.inner.borrow_mut().with(|state| state.tx.is_empty()) {
301 return Ok(());
302 }
303 }
304 }
305
239 async fn inner_fill_buf<'a>(&'a self) -> Result<&'a [u8], Error> { 306 async fn inner_fill_buf<'a>(&'a self) -> Result<&'a [u8], Error> {
240 poll_fn(move |cx| { 307 poll_fn(move |cx| {
241 self.inner.borrow_mut().with(|state| { 308 self.inner.borrow_mut().with(|state| {
@@ -419,3 +486,35 @@ impl<'u, 'd, T: BasicInstance> embedded_io::asynch::Write for BufferedUartTx<'u,
419 self.inner.inner_flush().await 486 self.inner.inner_flush().await
420 } 487 }
421} 488}
489
490impl<'d, T: BasicInstance> embedded_io::blocking::Read for BufferedUart<'d, T> {
491 fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
492 self.inner_blocking_read(buf)
493 }
494}
495
496impl<'u, 'd, T: BasicInstance> embedded_io::blocking::Read for BufferedUartRx<'u, 'd, T> {
497 fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
498 self.inner.inner_blocking_read(buf)
499 }
500}
501
502impl<'d, T: BasicInstance> embedded_io::blocking::Write for BufferedUart<'d, T> {
503 fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
504 self.inner_blocking_write(buf)
505 }
506
507 fn flush(&mut self) -> Result<(), Self::Error> {
508 self.inner_blocking_flush()
509 }
510}
511
512impl<'u, 'd, T: BasicInstance> embedded_io::blocking::Write for BufferedUartTx<'u, 'd, T> {
513 fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
514 self.inner.inner_blocking_write(buf)
515 }
516
517 fn flush(&mut self) -> Result<(), Self::Error> {
518 self.inner.inner_blocking_flush()
519 }
520}
diff --git a/embassy-sync/src/pipe.rs b/embassy-sync/src/pipe.rs
index 1977005fb..ee27cdec8 100644
--- a/embassy-sync/src/pipe.rs
+++ b/embassy-sync/src/pipe.rs
@@ -32,16 +32,16 @@ impl<'p, M, const N: usize> Writer<'p, M, N>
32where 32where
33 M: RawMutex, 33 M: RawMutex,
34{ 34{
35 /// Writes a value. 35 /// Write some bytes to the pipe.
36 /// 36 ///
37 /// See [`Pipe::write()`] 37 /// See [`Pipe::write()`]
38 pub fn write<'a>(&'a self, buf: &'a [u8]) -> WriteFuture<'a, M, N> { 38 pub fn write<'a>(&'a self, buf: &'a [u8]) -> WriteFuture<'a, M, N> {
39 self.pipe.write(buf) 39 self.pipe.write(buf)
40 } 40 }
41 41
42 /// Attempt to immediately write a message. 42 /// Attempt to immediately write some bytes to the pipe.
43 /// 43 ///
44 /// See [`Pipe::write()`] 44 /// See [`Pipe::try_write()`]
45 pub fn try_write(&self, buf: &[u8]) -> Result<usize, TryWriteError> { 45 pub fn try_write(&self, buf: &[u8]) -> Result<usize, TryWriteError> {
46 self.pipe.try_write(buf) 46 self.pipe.try_write(buf)
47 } 47 }
@@ -95,16 +95,16 @@ impl<'p, M, const N: usize> Reader<'p, M, N>
95where 95where
96 M: RawMutex, 96 M: RawMutex,
97{ 97{
98 /// Reads a value. 98 /// Read some bytes from the pipe.
99 /// 99 ///
100 /// See [`Pipe::read()`] 100 /// See [`Pipe::read()`]
101 pub fn read<'a>(&'a self, buf: &'a mut [u8]) -> ReadFuture<'a, M, N> { 101 pub fn read<'a>(&'a self, buf: &'a mut [u8]) -> ReadFuture<'a, M, N> {
102 self.pipe.read(buf) 102 self.pipe.read(buf)
103 } 103 }
104 104
105 /// Attempt to immediately read a message. 105 /// Attempt to immediately read some bytes from the pipe.
106 /// 106 ///
107 /// See [`Pipe::read()`] 107 /// See [`Pipe::try_read()`]
108 pub fn try_read(&self, buf: &mut [u8]) -> Result<usize, TryReadError> { 108 pub fn try_read(&self, buf: &mut [u8]) -> Result<usize, TryReadError> {
109 self.pipe.try_read(buf) 109 self.pipe.try_read(buf)
110 } 110 }
@@ -221,12 +221,11 @@ impl<const N: usize> PipeState<N> {
221 } 221 }
222} 222}
223 223
224/// A bounded pipe for communicating between asynchronous tasks 224/// A bounded byte-oriented pipe for communicating between asynchronous tasks
225/// with backpressure. 225/// with backpressure.
226/// 226///
227/// The pipe will buffer up to the provided number of messages. Once the 227/// The pipe will buffer up to the provided number of bytes. Once the
228/// buffer is full, attempts to `write` new messages will wait until a message is 228/// buffer is full, attempts to `write` new bytes will wait until buffer space is freed up.
229/// read from the pipe.
230/// 229///
231/// All data written will become available in the same order as it was written. 230/// All data written will become available in the same order as it was written.
232pub struct Pipe<M, const N: usize> 231pub struct Pipe<M, const N: usize>
@@ -277,40 +276,56 @@ where
277 Reader { pipe: self } 276 Reader { pipe: self }
278 } 277 }
279 278
280 /// Write a value, waiting until there is capacity. 279 /// Write some bytes to the pipe.
280 ///
281 /// This method writes a nonzero amount of bytes from `buf` into the pipe, and
282 /// returns the amount of bytes written.
283 ///
284 /// If it is not possible to write a nonzero amount of bytes because the pipe's buffer is full,
285 /// this method will wait until it is. See [`try_write`](Self::try_write) for a variant that
286 /// returns an error instead of waiting.
281 /// 287 ///
282 /// Writeing completes when the value has been pushed to the pipe's queue. 288 /// It is not guaranteed that all bytes in the buffer are written, even if there's enough
283 /// This doesn't mean the value has been read yet. 289 /// free space in the pipe buffer for all. In other words, it is possible for `write` to return
290 /// without writing all of `buf` (returning a number less than `buf.len()`) and still leave
291 /// free space in the pipe buffer. You should always `write` in a loop, or use helpers like
292 /// `write_all` from the `embedded-io` crate.
284 pub fn write<'a>(&'a self, buf: &'a [u8]) -> WriteFuture<'a, M, N> { 293 pub fn write<'a>(&'a self, buf: &'a [u8]) -> WriteFuture<'a, M, N> {
285 WriteFuture { pipe: self, buf } 294 WriteFuture { pipe: self, buf }
286 } 295 }
287 296
288 /// Attempt to immediately write a message. 297 /// Attempt to immediately write some bytes to the pipe.
289 /// 298 ///
290 /// This method differs from [`write`](Pipe::write) by returning immediately if the pipe's 299 /// This method will either write a nonzero amount of bytes to the pipe immediately,
291 /// buffer is full, instead of waiting. 300 /// or return an error if the pipe is empty. See [`write`](Self::write) for a variant
292 /// 301 /// that waits instead of returning an error.
293 /// # Errors
294 ///
295 /// If the pipe capacity has been reached, i.e., the pipe has `n`
296 /// buffered values where `n` is the argument passed to [`Pipe`], then an
297 /// error is returned.
298 pub fn try_write(&self, buf: &[u8]) -> Result<usize, TryWriteError> { 302 pub fn try_write(&self, buf: &[u8]) -> Result<usize, TryWriteError> {
299 self.lock(|c| c.try_write(buf)) 303 self.lock(|c| c.try_write(buf))
300 } 304 }
301 305
302 /// Receive the next value. 306 /// Read some bytes from the pipe.
307 ///
308 /// This method reads a nonzero amount of bytes from the pipe into `buf` and
309 /// returns the amount of bytes read.
310 ///
311 /// If it is not possible to read a nonzero amount of bytes because the pipe's buffer is empty,
312 /// this method will wait until it is. See [`try_read`](Self::try_read) for a variant that
313 /// returns an error instead of waiting.
303 /// 314 ///
304 /// If there are no messages in the pipe's buffer, this method will 315 /// It is not guaranteed that all bytes in the buffer are read, even if there's enough
305 /// wait until a message is written. 316 /// space in `buf` for all. In other words, it is possible for `read` to return
317 /// without filling `buf` (returning a number less than `buf.len()`) and still leave bytes
318 /// in the pipe buffer. You should always `read` in a loop, or use helpers like
319 /// `read_exact` from the `embedded-io` crate.
306 pub fn read<'a>(&'a self, buf: &'a mut [u8]) -> ReadFuture<'a, M, N> { 320 pub fn read<'a>(&'a self, buf: &'a mut [u8]) -> ReadFuture<'a, M, N> {
307 ReadFuture { pipe: self, buf } 321 ReadFuture { pipe: self, buf }
308 } 322 }
309 323
310 /// Attempt to immediately read a message. 324 /// Attempt to immediately read some bytes from the pipe.
311 /// 325 ///
312 /// This method will either read a message from the pipe immediately or return an error 326 /// This method will either read a nonzero amount of bytes from the pipe immediately,
313 /// if the pipe is empty. 327 /// or return an error if the pipe is empty. See [`read`](Self::read) for a variant
328 /// that waits instead of returning an error.
314 pub fn try_read(&self, buf: &mut [u8]) -> Result<usize, TryReadError> { 329 pub fn try_read(&self, buf: &mut [u8]) -> Result<usize, TryReadError> {
315 self.lock(|c| c.try_read(buf)) 330 self.lock(|c| c.try_read(buf))
316 } 331 }
diff --git a/embassy-usb/src/builder.rs b/embassy-usb/src/builder.rs
index 305dfa02e..6b68bcd7b 100644
--- a/embassy-usb/src/builder.rs
+++ b/embassy-usb/src/builder.rs
@@ -201,6 +201,14 @@ impl<'d, D: Driver<'d>> Builder<'d, D> {
201 self.config_descriptor.end_configuration(); 201 self.config_descriptor.end_configuration();
202 self.bos_descriptor.end_bos(); 202 self.bos_descriptor.end_bos();
203 203
204 // Log the number of allocator bytes actually used in descriptor buffers
205 info!("USB: device_descriptor used: {}", self.device_descriptor.position());
206 info!("USB: config_descriptor used: {}", self.config_descriptor.position());
207 info!("USB: bos_descriptor used: {}", self.bos_descriptor.writer.position());
208 #[cfg(feature = "msos-descriptor")]
209 info!("USB: msos_descriptor used: {}", msos_descriptor.len());
210 info!("USB: control_buf size: {}", self.control_buf.len());
211
204 UsbDevice::build( 212 UsbDevice::build(
205 self.driver, 213 self.driver,
206 self.config, 214 self.config,
diff --git a/embassy-usb/src/class/hid.rs b/embassy-usb/src/class/hid.rs
index 974268c62..03e4c1dbb 100644
--- a/embassy-usb/src/class/hid.rs
+++ b/embassy-usb/src/class/hid.rs
@@ -458,6 +458,9 @@ impl<'d> Handler for Control<'d> {
458 return None; 458 return None;
459 } 459 }
460 460
461 // This uses a defmt-specific formatter that causes use of the `log`
462 // feature to fail to build, so leave it defmt-specific for now.
463 #[cfg(feature = "defmt")]
461 trace!("HID control_out {:?} {=[u8]:x}", req, data); 464 trace!("HID control_out {:?} {=[u8]:x}", req, data);
462 match req.request { 465 match req.request {
463 HID_REQ_SET_IDLE => { 466 HID_REQ_SET_IDLE => {
diff --git a/embassy-usb/src/lib.rs b/embassy-usb/src/lib.rs
index bfeccd5fe..3016b81cb 100644
--- a/embassy-usb/src/lib.rs
+++ b/embassy-usb/src/lib.rs
@@ -165,6 +165,25 @@ struct Interface {
165 num_alt_settings: u8, 165 num_alt_settings: u8,
166} 166}
167 167
168/// A report of the used size of the runtime allocated buffers
169#[derive(PartialEq, Eq, Copy, Clone, Debug)]
170#[cfg_attr(feature = "defmt", derive(defmt::Format))]
171pub struct UsbBufferReport {
172 /// Number of device descriptor bytes used
173 pub device_descriptor_used: usize,
174 /// Number of config descriptor bytes used
175 pub config_descriptor_used: usize,
176 /// Number of bos descriptor bytes used
177 pub bos_descriptor_used: usize,
178 /// Number of msos descriptor bytes used
179 ///
180 /// Will be `None` if the "msos-descriptor" feature is not active.
181 /// Otherwise will return Some(bytes).
182 pub msos_descriptor_used: Option<usize>,
183 /// Size of the control buffer
184 pub control_buffer_size: usize,
185}
186
168/// Main struct for the USB device stack. 187/// Main struct for the USB device stack.
169pub struct UsbDevice<'d, D: Driver<'d>> { 188pub struct UsbDevice<'d, D: Driver<'d>> {
170 control_buf: &'d mut [u8], 189 control_buf: &'d mut [u8],
@@ -239,6 +258,24 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
239 } 258 }
240 } 259 }
241 260
261 /// Returns a report of the consumed buffers
262 ///
263 /// Useful for tuning buffer sizes for actual usage
264 pub fn buffer_usage(&self) -> UsbBufferReport {
265 #[cfg(not(feature = "msos-descriptor"))]
266 let mdu = None;
267 #[cfg(feature = "msos-descriptor")]
268 let mdu = Some(self.inner.msos_descriptor.len());
269
270 UsbBufferReport {
271 device_descriptor_used: self.inner.device_descriptor.len(),
272 config_descriptor_used: self.inner.config_descriptor.len(),
273 bos_descriptor_used: self.inner.bos_descriptor.len(),
274 msos_descriptor_used: mdu,
275 control_buffer_size: self.control_buf.len(),
276 }
277 }
278
242 /// Runs the `UsbDevice` forever. 279 /// Runs the `UsbDevice` forever.
243 /// 280 ///
244 /// This future may leave the bus in an invalid state if it is dropped. 281 /// This future may leave the bus in an invalid state if it is dropped.
diff --git a/embassy-usb/src/msos.rs b/embassy-usb/src/msos.rs
index b1e0335ee..218d9931a 100644
--- a/embassy-usb/src/msos.rs
+++ b/embassy-usb/src/msos.rs
@@ -32,6 +32,11 @@ impl<'d> MsOsDescriptorSet<'d> {
32 pub fn is_empty(&self) -> bool { 32 pub fn is_empty(&self) -> bool {
33 self.descriptor.is_empty() 33 self.descriptor.is_empty()
34 } 34 }
35
36 /// Returns the length of the descriptor field
37 pub fn len(&self) -> usize {
38 self.descriptor.len()
39 }
35} 40}
36 41
37/// Writes a Microsoft OS 2.0 Descriptor set into a buffer. 42/// Writes a Microsoft OS 2.0 Descriptor set into a buffer.
diff --git a/tests/rp/src/bin/spi_async.rs b/tests/rp/src/bin/spi_async.rs
index 6c85ef60a..2e22c9de7 100644
--- a/tests/rp/src/bin/spi_async.rs
+++ b/tests/rp/src/bin/spi_async.rs
@@ -1,3 +1,6 @@
1//! Make sure to connect GPIO pins 3 (`PIN_3`) and 4 (`PIN_4`) together
2//! to run this test.
3//!
1#![no_std] 4#![no_std]
2#![no_main] 5#![no_main]
3#![feature(type_alias_impl_trait)] 6#![feature(type_alias_impl_trait)]
@@ -18,10 +21,63 @@ async fn main(_spawner: Spawner) {
18 21
19 let mut spi = Spi::new(p.SPI0, clk, mosi, miso, p.DMA_CH0, p.DMA_CH1, Config::default()); 22 let mut spi = Spi::new(p.SPI0, clk, mosi, miso, p.DMA_CH0, p.DMA_CH1, Config::default());
20 23
21 let tx_buf = [1_u8, 2, 3, 4, 5, 6]; 24 // equal rx & tx buffers
22 let mut rx_buf = [0_u8; 6]; 25 {
23 spi.transfer(&mut rx_buf, &tx_buf).await.unwrap(); 26 let tx_buf = [1_u8, 2, 3, 4, 5, 6];
24 assert_eq!(rx_buf, tx_buf); 27 let mut rx_buf = [0_u8; 6];
28 spi.transfer(&mut rx_buf, &tx_buf).await.unwrap();
29 assert_eq!(rx_buf, tx_buf);
30 }
31
32 // tx > rx buffer
33 {
34 let tx_buf = [7_u8, 8, 9, 10, 11, 12];
35
36 let mut rx_buf = [0_u8; 3];
37 spi.transfer(&mut rx_buf, &tx_buf).await.unwrap();
38 assert_eq!(rx_buf, tx_buf[..3]);
39
40 defmt::info!("tx > rx buffer - OK");
41 }
42
43 // we make sure to that clearing FIFO works after the uneven buffers
44
45 // equal rx & tx buffers
46 {
47 let tx_buf = [13_u8, 14, 15, 16, 17, 18];
48 let mut rx_buf = [0_u8; 6];
49 spi.transfer(&mut rx_buf, &tx_buf).await.unwrap();
50 assert_eq!(rx_buf, tx_buf);
51
52 defmt::info!("buffer rx length == tx length - OK");
53 }
54
55 // rx > tx buffer
56 {
57 let tx_buf = [19_u8, 20, 21];
58 let mut rx_buf = [0_u8; 6];
59
60 // we should have written dummy data to tx buffer to sync clock.
61 spi.transfer(&mut rx_buf, &tx_buf).await.unwrap();
62
63 assert_eq!(
64 rx_buf[..3],
65 tx_buf,
66 "only the first 3 TX bytes should have been received in the RX buffer"
67 );
68 assert_eq!(rx_buf[3..], [0, 0, 0], "the rest of the RX bytes should be empty");
69 defmt::info!("buffer rx length > tx length - OK");
70 }
71
72 // equal rx & tx buffers
73 {
74 let tx_buf = [22_u8, 23, 24, 25, 26, 27];
75 let mut rx_buf = [0_u8; 6];
76 spi.transfer(&mut rx_buf, &tx_buf).await.unwrap();
77
78 assert_eq!(rx_buf, tx_buf);
79 defmt::info!("buffer rx length = tx length - OK");
80 }
25 81
26 info!("Test OK"); 82 info!("Test OK");
27 cortex_m::asm::bkpt(); 83 cortex_m::asm::bkpt();