diff options
| -rw-r--r-- | embassy-executor/src/raw/mod.rs | 179 | ||||
| -rw-r--r-- | embassy-executor/src/raw/timer_queue.rs | 14 | ||||
| -rw-r--r-- | embassy-executor/src/raw/util.rs | 29 | ||||
| -rw-r--r-- | embassy-executor/src/spawner.rs | 12 | ||||
| -rw-r--r-- | embassy-rp/src/dma.rs | 1 | ||||
| -rw-r--r-- | embassy-rp/src/spi.rs | 45 | ||||
| -rw-r--r-- | embassy-stm32/Cargo.toml | 2 | ||||
| -rw-r--r-- | embassy-stm32/src/adc/sample_time.rs | 13 | ||||
| -rw-r--r-- | embassy-stm32/src/usart/buffered.rs | 99 | ||||
| -rw-r--r-- | embassy-sync/src/pipe.rs | 71 | ||||
| -rw-r--r-- | embassy-usb/src/builder.rs | 8 | ||||
| -rw-r--r-- | embassy-usb/src/class/hid.rs | 3 | ||||
| -rw-r--r-- | embassy-usb/src/lib.rs | 37 | ||||
| -rw-r--r-- | embassy-usb/src/msos.rs | 5 | ||||
| -rw-r--r-- | tests/rp/src/bin/spi_async.rs | 64 |
15 files changed, 451 insertions, 131 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; | |||
| 13 | pub(crate) mod util; | 13 | pub(crate) mod util; |
| 14 | mod waker; | 14 | mod waker; |
| 15 | 15 | ||
| 16 | use core::cell::Cell; | ||
| 17 | use core::future::Future; | 16 | use core::future::Future; |
| 17 | use core::marker::PhantomData; | ||
| 18 | use core::mem; | 18 | use core::mem; |
| 19 | use core::pin::Pin; | 19 | use core::pin::Pin; |
| 20 | use core::ptr::NonNull; | 20 | use core::ptr::NonNull; |
| 21 | use core::sync::atomic::AtomicPtr; | ||
| 21 | use core::task::{Context, Poll}; | 22 | use core::task::{Context, Poll}; |
| 22 | 23 | ||
| 23 | use atomic_polyfill::{AtomicU32, Ordering}; | 24 | use atomic_polyfill::{AtomicU32, Ordering}; |
| @@ -30,7 +31,7 @@ use embassy_time::Instant; | |||
| 30 | use rtos_trace::trace; | 31 | use rtos_trace::trace; |
| 31 | 32 | ||
| 32 | use self::run_queue::{RunQueue, RunQueueItem}; | 33 | use self::run_queue::{RunQueue, RunQueueItem}; |
| 33 | use self::util::UninitCell; | 34 | use self::util::{SyncUnsafeCell, UninitCell}; |
| 34 | pub use self::waker::task_from_waker; | 35 | pub use self::waker::task_from_waker; |
| 35 | use super::SpawnToken; | 36 | use super::SpawnToken; |
| 36 | 37 | ||
| @@ -46,11 +47,11 @@ pub(crate) const STATE_TIMER_QUEUED: u32 = 1 << 2; | |||
| 46 | pub(crate) struct TaskHeader { | 47 | pub(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 | ||
| 65 | unsafe impl Send for TaskRef where &'static TaskHeader: Send {} | ||
| 66 | unsafe impl Sync for TaskRef where &'static TaskHeader: Sync {} | ||
| 67 | |||
| 64 | impl TaskRef { | 68 | impl 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 | ||
| 175 | unsafe 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 | ||
| 177 | struct AvailableTask<F: Future + 'static> { | 187 | struct 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. | 292 | pub(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. | ||
| 301 | pub 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 | ||
| 312 | impl Executor { | 303 | impl 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)] | ||
| 429 | pub struct Executor { | ||
| 430 | pub(crate) inner: SyncExecutor, | ||
| 431 | |||
| 432 | _not_sync: PhantomData<*mut ()>, | ||
| 433 | } | ||
| 434 | |||
| 435 | impl 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 @@ | |||
| 1 | use core::cell::Cell; | ||
| 2 | use core::cmp::min; | 1 | use core::cmp::min; |
| 3 | 2 | ||
| 4 | use atomic_polyfill::Ordering; | 3 | use atomic_polyfill::Ordering; |
| 5 | use embassy_time::Instant; | 4 | use embassy_time::Instant; |
| 6 | 5 | ||
| 7 | use super::{TaskRef, STATE_TIMER_QUEUED}; | 6 | use super::{TaskRef, STATE_TIMER_QUEUED}; |
| 7 | use crate::raw::util::SyncUnsafeCell; | ||
| 8 | 8 | ||
| 9 | pub(crate) struct TimerQueueItem { | 9 | pub(crate) struct TimerQueueItem { |
| 10 | next: Cell<Option<TaskRef>>, | 10 | next: SyncUnsafeCell<Option<TaskRef>>, |
| 11 | } | 11 | } |
| 12 | 12 | ||
| 13 | impl TimerQueueItem { | 13 | impl 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 | ||
| 19 | pub(crate) struct TimerQueue { | 21 | pub(crate) struct TimerQueue { |
| 20 | head: Cell<Option<TaskRef>>, | 22 | head: SyncUnsafeCell<Option<TaskRef>>, |
| 21 | } | 23 | } |
| 22 | 24 | ||
| 23 | impl TimerQueue { | 25 | impl 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 | |||
| 29 | unsafe impl<T> Sync for UninitCell<T> {} | ||
| 30 | |||
| 31 | #[repr(transparent)] | ||
| 32 | pub struct SyncUnsafeCell<T> { | ||
| 33 | value: UnsafeCell<T>, | ||
| 34 | } | ||
| 35 | |||
| 36 | unsafe impl<T: Sync> Sync for SyncUnsafeCell<T> {} | ||
| 37 | |||
| 38 | impl<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)] |
| 147 | pub struct SendSpawner { | 146 | pub struct SendSpawner { |
| 148 | executor: &'static raw::Executor, | 147 | executor: &'static raw::SyncExecutor, |
| 149 | } | 148 | } |
| 150 | 149 | ||
| 151 | unsafe impl Send for SendSpawner {} | ||
| 152 | unsafe impl Sync for SendSpawner {} | ||
| 153 | |||
| 154 | impl SendSpawner { | 150 | impl 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) | ||
| 1 | use core::future::Future; | 2 | use core::future::Future; |
| 2 | use core::pin::Pin; | 3 | use core::pin::Pin; |
| 3 | use core::sync::atomic::{compiler_fence, Ordering}; | 4 | use 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 | ||
| 1 | use core::marker::PhantomData; | 2 | use core::marker::PhantomData; |
| 2 | 3 | ||
| 3 | use embassy_embedded_hal::SetConfig; | 4 | use 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-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 1dd6202d3..1af439ebe 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml | |||
| @@ -75,7 +75,7 @@ critical-section = { version = "1.1", features = ["std"] } | |||
| 75 | [build-dependencies] | 75 | [build-dependencies] |
| 76 | proc-macro2 = "1.0.36" | 76 | proc-macro2 = "1.0.36" |
| 77 | quote = "1.0.15" | 77 | quote = "1.0.15" |
| 78 | stm32-metapac = { version = "1", default-features = false, features = ["metadata"]} | 78 | stm32-metapac = { version = "2", default-features = false, features = ["metadata"]} |
| 79 | 79 | ||
| 80 | [features] | 80 | [features] |
| 81 | default = ["stm32-metapac/rt"] | 81 | default = ["stm32-metapac/rt"] |
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 @@ | |||
| 1 | macro_rules! impl_sample_time { | 1 | macro_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 { | |||
| 29 | impl_sample_time!( | 29 | impl_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!( | |||
| 46 | impl_sample_time!( | 45 | impl_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!( | |||
| 63 | impl_sample_time!( | 61 | impl_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!( | |||
| 80 | impl_sample_time!( | 77 | impl_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!( | |||
| 97 | impl_sample_time!( | 93 | impl_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/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 | |||
| 490 | impl<'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 | |||
| 496 | impl<'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 | |||
| 502 | impl<'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 | |||
| 512 | impl<'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> | |||
| 32 | where | 32 | where |
| 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> | |||
| 95 | where | 95 | where |
| 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. |
| 232 | pub struct Pipe<M, const N: usize> | 231 | pub 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))] | ||
| 171 | pub 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. |
| 169 | pub struct UsbDevice<'d, D: Driver<'d>> { | 188 | pub 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(); |
